【发布时间】:2012-10-15 13:20:11
【问题描述】:
我有一个关于如何设计适合单元测试的应用程序的问题。
我正在尝试实施 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 传递给 DI 是否更有意义-framework,在获取IRecurringProfileNextPaymentCreator 的实例时,考虑到IRecurringProfileNextPaymentCreator 将始终作用于IRecurringProfile 以创建下一次付款。希望这能让问题更清楚一点。
【问题讨论】:
-
@KellyEthridge 将此作为答案而不是评论
标签: c# unit-testing dependency-injection ninject