使用c#类名创建ILogger<T>用于xUnit服务类初始化

问题描述 投票:0回答:1

我有一个包含数百个 C# 类文件的大型项目。需要为依赖于许多参数的服务功能编写 xUnit 测试,并且这些类之间可能存在依赖关系。在某些情况下,构造函数需要

ILogger<T>
。初始化这些依赖项以运行测试非常耗时。 有没有办法根据通过参数反射获得的类名来创建
ILogger<T>

1 - 获取所需参数

public static object CreateInstance(Type type, Assembly[] assemblies)
{
    try
    {
        var constructor = type.GetConstructors().FirstOrDefault();
        if (constructor == null)
        {
            throw new InvalidOperationException($"No public constructor found for type {type.FullName}");
        }

        var parameters = constructor.GetParameters();
        var parameterInstances = parameters.Select(p => ResolveDependency(p.ParameterType, assemblies)).ToArray();

        return constructor.Invoke(parameterInstances);
    }
    catch (Exception ex)
    {
        throw;
    }
}

2 - 解决依赖关系

private static object ResolveDependency(Type type, Assembly[] assemblies)
{
    if (type.Name.IndexOf("IMapper") > -1)
    {
        return AutoMapperConfig.GetMapper();
    }

    if (type.Name.IndexOf("ILogger") > -1)
    {
        try
        {
            var typeArg = type.GetGenericArguments()[0];
            var entityType = FindTypeByName(typeArg.Name, assemblies);                    
            return LoggerFactory.CreateLogger<entityType.GetType()>();
        }
        catch (Exception ex1)
        {
            throw;
        }
    }

    foreach (var assembly in assemblies)
    {
        var implementationType = assembly.GetTypes().FirstOrDefault(t => type.IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);
        if (implementationType != null)
        {
            return CreateInstance(implementationType, assemblies);
        }
    }

    throw new InvalidOperationException($"No implementation found for type {type.FullName}");
}

3 - 记录器实例 - 失败

public static object CreateILogger(Type type)
{            
    var genericType = typeof(Logger<>).MakeGenericType(type);
    return Activator.CreateInstance(genericType);
}

我的目标是对于每个服务类别,我都会致电

var myService = ServiceInitializer.Initialize(MyService);

底层函数“Initialize”将收集所需的参数并迭代到最后一个参数并初始化它们。我明确忽略除我们编写的 DLL 之外的所有 DLL。

可能我选择了错误的方法来编写 XUnit 测试,非常需要您的建议,只要记住我想摆脱初始化n个类来测试一项服务。

automated-tests xunit.net ilogger
1个回答
0
投票

如果我没猜错的话,已经有图书馆在为你做这项工作了:)

让我们考虑示例设置:

public interface IService1 { }
public class Service1 : IService1 { }
public interface IService2 { }
public class Service2 : IService2 { }

public class Sut 
{
    private readonly IService1 service1;
    private readonly IService2 service2;

    public Sut(IService1 service1, IService2 service2)
    {
        this.service1 = service1;
        this.service2 = service2;
    }
};

然后,如果你想测试

Sut
,但不关心依赖关系(这是好的实践),那么你只需要模拟它们。

您可以开始创建

Mock<>
对象,但这又会很麻烦。但有 nuget 包:

  • 自动夹具
  • 自动夹具.AutoMoq

它们允许“自动魔术”创建对象。带有注释的单元测试中的示例用法:

public class UnitTest1
{
    // Here AutoMoqCustomization enables Fixture to create 
    // mocks of interfaces.
    private readonly IFixture _fixture = new Fixture().Customize(new AutoMoqCustomization());

    [Fact]
    public async Task Test1()
    {
        // Will automatically crweate Sut object and pass
        // mockaed interfaces to constructor
        var sut = _fixture.Create<Sut>();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.