Model Testing
I like this Model Tester for unit testing.
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
namespace QT.RemoteOrder.API.Tests;
[ExcludeFromCodeCoverage]
internal static class ModelTesting
{
public static void TestMockData<T>(T model) where T : class
{
var type = typeof(T);
foreach (var propertyInfo in type.GetProperties())
{
var propertyTypeName = GetTypeFromPropertyInfo(propertyInfo);
switch (propertyTypeName)
{
case "System.String":
Assert.IsNotNull(propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
break;
case "System.Char":
Assert.IsNotNull(propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
break;
case "System.DateTime":
Assert.AreNotEqual(DateTime.MinValue, propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
break;
case "System.TimeSpan":
Assert.AreNotEqual(TimeSpan.MinValue, propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
break;
case "System.Double":
case "System.Decimal":
case "System.Int32":
case "System.Int64":
case "System.Int16":
case "System.Byte":
Assert.AreNotEqual(0, propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
break;
case "System.Boolean":
Assert.IsTrue(bool.Parse(propertyInfo.GetValue(model)?.ToString() ?? string.Empty), $"Class: {type.Name} Property: {propertyInfo.Name}");
break;
case "System.Guid":
Assert.AreNotEqual(Guid.Empty, propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
break;
default:
if (propertyTypeName.StartsWith("QT."))
{
Assert.IsNotNull(propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
}
else if (propertyTypeName.StartsWith("System.Collections.Generic.List"))
{
Assert.IsNotNull(propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
}
else if (propertyTypeName.StartsWith("System.Collections.Generic"))
{
Assert.IsNotNull(propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
}
break;
}
}
}
public static T GenerateMockData<T>() where T : class
{
return GenerateMockData<T>(1).First();
}
public static List<T> GenerateMockData<T>(int count) where T : class
{
var mockData = new List<T>();
var random = new Random();
var type = typeof(T);
for (var i = 1; i <= count; i++)
{
T mock = (T)Activator.CreateInstance(type)!;
foreach (var propertyInfo in type.GetProperties())
{
if (!propertyInfo.CanWrite) continue;
var propertyTypeName = GetTypeFromPropertyInfo(propertyInfo);
switch (propertyTypeName)
{
case "System.String":
var newString = RandomString();
if (propertyInfo.Name.Contains("email", StringComparison.InvariantCultureIgnoreCase))
{
newString = $"{RandomString(10)}@{RandomString(5)}.{RandomString(3)}";
}
propertyInfo.SetValue(mock, newString);
break;
case "System.Char":
propertyInfo.SetValue(mock, char.Parse(RandomString(1)));
break;
case "System.DateTime":
propertyInfo.SetValue(mock, DateTime.UtcNow.AddSeconds(30));
break;
case "System.DateOnly":
propertyInfo.SetValue(mock, DateOnly.FromDateTime(DateTime.UtcNow));
break;
case "System.TimeSpan":
propertyInfo.SetValue(mock, TimeSpan.FromMinutes(DateTime.Now.Second + 1));
break;
case "System.Double":
propertyInfo.SetValue(mock, random.NextDouble() * 100 + 1);
break;
case "System.Decimal":
propertyInfo.SetValue(mock, (decimal)random.NextDouble() * 100 + 1);
break;
case "System.Int32":
propertyInfo.SetValue(mock, random.Next(1, 32760));
break;
case "System.Int64":
propertyInfo.SetValue(mock, (Int64)random.Next(1, 1024));
break;
case "System.Int16":
propertyInfo.SetValue(mock, (Int16)random.Next(1, 32760));
break;
case "System.Byte":
propertyInfo.SetValue(mock, (byte)random.Next(1, 8));
break;
case "System.Boolean":
propertyInfo.SetValue(mock, true);
break;
case "System.Guid":
propertyInfo.SetValue(mock, Guid.NewGuid());
break;
default:
if (propertyTypeName.StartsWith("QT."))
{
var newObject = Activator.CreateInstance(propertyInfo.PropertyType);
propertyInfo.SetValue(mock, newObject);
}
break;
}
}
mockData.Add(mock);
}
return mockData;
}
public static string RandomString(int length = 25)
{
var random = new Random();
var randomString = "";
for (int i = 0; i < length; i++)
{
randomString += Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))).ToString();
}
return randomString;
}
private static string GetTypeFromPropertyInfo(PropertyInfo propertyInfo, bool all = false)
{
if (propertyInfo.PropertyType.ToString()
.Contains("NULLABLE", StringComparison.InvariantCultureIgnoreCase))
{
var theTypeParts = propertyInfo.PropertyType.ToString().Replace("]", string.Empty).Split("[");
return theTypeParts[1];
}
if (all)
{
var theTypeParts = propertyInfo.PropertyType.ToString().Replace("]", string.Empty).Split("[");
return theTypeParts[1];
}
return propertyInfo.PropertyType.ToString();
}
}
using System.Reflection;
namespace QT.RemoteOrder.API.Tests;
[ExcludeFromCodeCoverage]
internal static class ModelTesting
{
public static void TestMockData<T>(T model) where T : class
{
var type = typeof(T);
foreach (var propertyInfo in type.GetProperties())
{
var propertyTypeName = GetTypeFromPropertyInfo(propertyInfo);
switch (propertyTypeName)
{
case "System.String":
Assert.IsNotNull(propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
break;
case "System.Char":
Assert.IsNotNull(propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
break;
case "System.DateTime":
Assert.AreNotEqual(DateTime.MinValue, propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
break;
case "System.TimeSpan":
Assert.AreNotEqual(TimeSpan.MinValue, propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
break;
case "System.Double":
case "System.Decimal":
case "System.Int32":
case "System.Int64":
case "System.Int16":
case "System.Byte":
Assert.AreNotEqual(0, propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
break;
case "System.Boolean":
Assert.IsTrue(bool.Parse(propertyInfo.GetValue(model)?.ToString() ?? string.Empty), $"Class: {type.Name} Property: {propertyInfo.Name}");
break;
case "System.Guid":
Assert.AreNotEqual(Guid.Empty, propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
break;
default:
if (propertyTypeName.StartsWith("QT."))
{
Assert.IsNotNull(propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
}
else if (propertyTypeName.StartsWith("System.Collections.Generic.List"))
{
Assert.IsNotNull(propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
}
else if (propertyTypeName.StartsWith("System.Collections.Generic"))
{
Assert.IsNotNull(propertyInfo.GetValue(model), $"Class: {type.Name} Property: {propertyInfo.Name}");
}
break;
}
}
}
public static T GenerateMockData<T>() where T : class
{
return GenerateMockData<T>(1).First();
}
public static List<T> GenerateMockData<T>(int count) where T : class
{
var mockData = new List<T>();
var random = new Random();
var type = typeof(T);
for (var i = 1; i <= count; i++)
{
T mock = (T)Activator.CreateInstance(type)!;
foreach (var propertyInfo in type.GetProperties())
{
if (!propertyInfo.CanWrite) continue;
var propertyTypeName = GetTypeFromPropertyInfo(propertyInfo);
switch (propertyTypeName)
{
case "System.String":
var newString = RandomString();
if (propertyInfo.Name.Contains("email", StringComparison.InvariantCultureIgnoreCase))
{
newString = $"{RandomString(10)}@{RandomString(5)}.{RandomString(3)}";
}
propertyInfo.SetValue(mock, newString);
break;
case "System.Char":
propertyInfo.SetValue(mock, char.Parse(RandomString(1)));
break;
case "System.DateTime":
propertyInfo.SetValue(mock, DateTime.UtcNow.AddSeconds(30));
break;
case "System.DateOnly":
propertyInfo.SetValue(mock, DateOnly.FromDateTime(DateTime.UtcNow));
break;
case "System.TimeSpan":
propertyInfo.SetValue(mock, TimeSpan.FromMinutes(DateTime.Now.Second + 1));
break;
case "System.Double":
propertyInfo.SetValue(mock, random.NextDouble() * 100 + 1);
break;
case "System.Decimal":
propertyInfo.SetValue(mock, (decimal)random.NextDouble() * 100 + 1);
break;
case "System.Int32":
propertyInfo.SetValue(mock, random.Next(1, 32760));
break;
case "System.Int64":
propertyInfo.SetValue(mock, (Int64)random.Next(1, 1024));
break;
case "System.Int16":
propertyInfo.SetValue(mock, (Int16)random.Next(1, 32760));
break;
case "System.Byte":
propertyInfo.SetValue(mock, (byte)random.Next(1, 8));
break;
case "System.Boolean":
propertyInfo.SetValue(mock, true);
break;
case "System.Guid":
propertyInfo.SetValue(mock, Guid.NewGuid());
break;
default:
if (propertyTypeName.StartsWith("QT."))
{
var newObject = Activator.CreateInstance(propertyInfo.PropertyType);
propertyInfo.SetValue(mock, newObject);
}
break;
}
}
mockData.Add(mock);
}
return mockData;
}
public static string RandomString(int length = 25)
{
var random = new Random();
var randomString = "";
for (int i = 0; i < length; i++)
{
randomString += Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))).ToString();
}
return randomString;
}
private static string GetTypeFromPropertyInfo(PropertyInfo propertyInfo, bool all = false)
{
if (propertyInfo.PropertyType.ToString()
.Contains("NULLABLE", StringComparison.InvariantCultureIgnoreCase))
{
var theTypeParts = propertyInfo.PropertyType.ToString().Replace("]", string.Empty).Split("[");
return theTypeParts[1];
}
if (all)
{
var theTypeParts = propertyInfo.PropertyType.ToString().Replace("]", string.Empty).Split("[");
return theTypeParts[1];
}
return propertyInfo.PropertyType.ToString();
}
}
The unit tests look like:
using System.Diagnostics.CodeAnalysis;
using XXX.Tests;
using XXX.Models;
namespace XXX.Tests.ModelTests;
[ExcludeFromCodeCoverage]
[TestClass]
public class XXXTests
{
[TestMethod]
public void XXX_Constructor()
{
var model = new XXX();
Assert.IsInstanceOfType(model, typeof(XXX));
}
[TestMethod]
public void XXX_Properties()
{
var models = ModelTesting.GenerateMockData<XXX>(3);
foreach (var model in models)
{
ModelTesting.TestMockData(model);
}
}
}
Comments
Post a Comment