我有一个关于如何设计适合单元测试的应用程序的问题。
我正在尝试实现 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/