单元测试中的依赖注入,xUnit

Dependency injection in unit testing, xUnit

这可能是一个愚蠢的问题,但我正经历其中的一天。

我有一个名为 JwtManager 的 class 和一个名为 IJwtManager 的接口,我正在尝试将接口注入单元测试 class 以便我可以测试它但它不起作用,编译器给我这条消息:The following constructor parameters did not have matching fixture data: IJwtManager jwtManager.

我认为问题在于编译器不知道 class 应该将接口映射到什么,但是我如何在测试 class 中编写 services.AddScoped<>() 的等价物?

测试代码示例class:

public class JwtManagerTests
{
    private readonly IJwtManager jwtManager;
    public JwtManagerTests(IJwtManager jwtManager)
    {
        this.jwtManager = jwtManager;
    }

    [Fact]
    public void Test_Something()
    {
        // Test here
    }
}

将 DI 容器与单元测试项目一起使用是可能的,但确实有点矫枉过正。它迫使您在测试之间共享依赖关系,这使得调整依赖关系的行为以适应特定测试变得更加困难,因为您最终会破坏其他测试。

相反,我们应该努力在我们的测试方法中定义被测系统的依赖关系。您提到您的 JwtManager class 依赖于 IConfiguration。没问题。

[Fact]
public void JwtManagerShouldCreateJwtWhenDetailsAreValid()
{
    // Arrange
    var configuration = new ConfigurationBuilder().AddInMemoryCollection(
    new Dictionary<string, string>
    {
        { "section:key1", "value1" },
        { "section:key2", "value2"}
    }).Build();

    var jwtManager = new JwtManager(configuration);

    // Act
    var result = jwtManager.CreateJwt("some input");

    // Assert
    result.Should().BeAValidJwt();
}

这样做的一个好处是您不必向配置对象添加任何配置,除了测试需要的配置。如果 JwtManager 的不同测试需要不同的配置设置来测试不同的场景,那现在很容易做到,因为配置不是来自单个 IoC 容器。

不过,我要提醒您不要直接依赖 classes 中的 IConfiguration。依赖强类型 class 通常更好。它使依赖关系更加清晰(您不必打开 JwtManager 来查看它会使用 IConfiguration 中的哪些设置)并且语法在测试中更清晰。例如:

public class JwtManagerSettings
{
    public string SomeSetting { get; set; }

    public int SomeOtherSetting { get; set; }
}

public class JwtManager
{
    readonly JwtManagerSettings _settings;

    public JwtManager(JwtManagerSettings settings)
    {
        _settings = settings;
    }
}

[Fact]
public void JwtManagerShouldCreateJwtWhenDetailsAreValid()
{
    // Arrange
    var settings = new JwtManagerSettings
    {
        SomeSetting = "abc",
        SomeOtherSettings = 123
    };

    var jwtManager = new JwtManager(settings);

    // Act
    var result = jwtManager.CreateJwt("some input");

    // Assert
    result.Should().BeAValidJwt();
}

在您的实际应用中,Microsoft.Extensions.Configuration 完全能够从 IConfiguration 中解析 JwtManagerSettings 等复杂类型。无论您在哪里配置 IoC 容器(例如 Startup.cs),您都可以这样做:

//assuming your settings are defined in a JSON key called "JwtManager"
var jwtManagerSettings = configuration.Get<JwtManagerSettings>("JwtManager");
services.AddSingleton(jwtManagerSettings);
{
    "JwtManager": {
        "SomeSetting": "abc",
        "SomeOtherSetting": 123
    }
}