我有一个关于如何设计适合单元测试的应用程序的问题。
我正在尝试实施 SRP(单一职责原则),据我了解,这涉及将大多数功能拆分为单独的专用类,以使代码更有条理。例如,我有这个特定的场景。
一个类RecurringProfile
,它有一个方法.ActivateProfile()
。此方法的作用是将状态标记为已激活,并为下一个到期日创建下一个(第一次)定期付款。例如,我将拆分功能以在单独的类中创建下一次定期付款RecurringProfileNextPaymentCreator
。我的即时想法是让这个类'RecurringProfile'
在它的构造函数中作为参数:
RecurringProfileNextPaymentCreator(IRecurringProfile profile)
但是,我认为这对于单元测试来说是有问题的。我想创建一个测试ActivateProfile
功能的单元测试。此方法将通过依赖注入 (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
在获取IRecurringProfileNextPaymentCreator
,考虑到IRecurringProfileNextPaymentCreator
将始终对 anIRecurringProfile
进行操作以创建下一笔付款。希望这能让问题更清楚一些。