c# - 单元测试和构造函数依赖注入(inject)

标签 c# unit-testing dependency-injection ninject

我有一个关于如何设计适合单元测试的应用程序的问题。

我正在尝试实现 SRP(单一职责原则),据我了解,这涉及将大部分功能拆分到单独的专用类中,以使代码更有条理。例如,我有这个特定的场景。

RecurringProfile,它有一个方法.ActivateProfile()。此方法的作用是将状态标记为已激活,并为下一个到期日创建下一个(第一个)定期付款。我打算拆分功能以在单独的类中创建下一个定期付款,例如 RecurringProfileNextPaymentCreator。我的即时想法是让此类将 'RecurringProfile' 作为其构造函数中的参数:

RecurringProfileNextPaymentCreator(IRecurringProfile profile)

但是,我认为这对于单元测试来说会有问题。我想创建一个单元测试来测试 ActivateProfile 功能。此方法将通过依赖注入(inject) (Ninject) 获取 IRecurringProfileNextPaymentCreator 的实例,并调用方法 .CreateNextPayment

我创建单元测试的想法是创建一个 IRecurringProfileNextPaymentCreator 的模拟,并替换它以便我可以验证 .ActivateProfile() 实际调用方法。但是,由于构造函数参数,这不适合作为 NInject 的默认构造函数。必须为这种情况创建自定义 NInject 提供程序(我可以在整个解决方案中使用许多此类类)会有点矫枉过正。

有什么想法/最佳实践可以解决这个问题吗?

-- 以下是关于上述示例的示例代码:(请注意代码是手写的,语法上并非 100% 正确)

public class RecurringProfile
{
    public void ActivateProfile()
    {
        this.Status = Enums.ProfileStatus.Activated;
        //now it should create the first recurring payment
        IRecurringProfileNextPaymentCreator creator = NInject.Get<IRecurringProfileNextPaymentCreator>();
        creator.CreateNextPayment(this); //this is what I'm having an issue about 
    }
}

和一个样本单元测试:

public void TestActivateProfile()
{   
    var mockPaymentCreator = new Mock<IRecurringProfileNextPaymentCreator>();
    NInject.Bind<IRecurringProfileNextPaymentCreator>(mockPaymentCreator.Object);

    RecurringProfile profile = new RecurringProfile();
    profile.ActivateProfile();
    Assert.That(profile.Status == Enums.ProfileStatus.Activated);
    mockPayment.Verify(x => x.CreateNextPayment(), Times.Once());

}

转到示例代码,我的问题是将 RecurringProfile 作为参数传递给 creator.CreateNextPayment() 方法是否是一个好习惯,或者是否更有意义以某种方式将 RecurringProfile 传递给 DI 框架,当获取 IRecurringProfileNextPaymentCreator 实例时,考虑到 IRecurringProfileNextPaymentCreator 将始终作用于 >IRecurringProfile 创建下一次付款。希望这能让问题更清楚一些。

最佳答案

在此类单元测试期间,您不应该使用 DI 容器 (Ninject)。在更新被测类时,您将手动注入(inject)模拟对象。然后验证调用是在模拟上进行的。

关于c# - 单元测试和构造函数依赖注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12896480/

相关文章:

c# - IOC/DI CaSTLeWindsor 每次都返回相同的实例

javascript - 类型错误 : Cannot read property 'get' of undefined Angularjs

C#项目附加输出路径

c# - 为什么 Console.Writeline、Console.Write 在 Visual Studio Express 中不起作用?

php - Laravel 单元测试 - 根据测试方法更改配置值

python - Python3 单元测试中的 Proxyquire 等效项

c# - 如何打破存储库之间的循环依赖

c# - 不想引发异常,是否应该返回一个包含bool和string数组的自定义类?

c# - 了解 WCF ServiceBehaviorProperty ConcurrencyMode

Python 测试 - init 处的模拟模块