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();
    }
}

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

Popular posts from this blog

Upgrading to .NET8 from desktop versions 4.8.X

GHL Chat Bots for Webpage

GHL > Set website so shorter URL address