【发布时间】:2018-05-22 10:25:50
【问题描述】:
我有一些遗留代码并针对我对该代码所做的增强编写测试。我有一个类 SiteSession 并提取了一个接口 ISiteSession,因此可以将依赖项注入到调用类中。
public class SiteSession : ISiteSession
{
public SiteSession(string userName, string externalRef, IePermitProAdapterClient ePermitService)
{
//.......
}
//...
}
调用类有一个构造函数,其中依赖项被注入到正在测试的控制器 CustomerDetails 中
private readonly ICustomerDetails _customerDetails;
private ISiteSession _siteSession;
public SsoController(ICustomerDetails customerDetails, ISiteSession siteSession)
{
_customerDetails = customerDetails;
_siteSession = siteSession;
}
public ActionResult CustomerDetails(CustomerDetails customerDetails)
{
//.....
//...
//...
_siteSession = new SiteSession(customer.Username, customer.CustomerRef, ePermitService);
//.....
//...
//...
}
现在我的测试方法已经模拟了依赖项,我对为此控制器或代码的任何其他部分创建的任何测试都没有问题。但是当调用这个控制器CustomerDetails 上的测试时,实际的构造函数调用是对SiteSession 类进行的,我无法注入模拟并中断真正的调用。我的测试代码如下:
private Mock<ISiteSession> _siteSession;
在测试设置方法中:_siteSession = new Mock<ISiteSession>();
并且在测试方法中:_siteSession.Setup(x => x.Token).Returns("TestToken");
我尝试了类似的方法:
_siteSession = new Mock<SiteSession>(_customer.Object.Username, _customer.Object.CustomerRef, null);
由于转换中的类型不同,这显然是不正确的,我无法想到如何模拟 SiteSession 类,以便不调用实际的构造函数。我正在使用 NInject、NUnit 和 Moq
【问题讨论】:
-
这是一个设计问题。通过在控制器中手动创建实例,控制器与实现紧密耦合,这使得模拟变得非常困难。查看您的设计选择,因为当前示例在最终目标方面不是很清楚。
-
提供适当单元测试的难度应该是设计问题的直接指标。
-
这正是我的想法,但仍然不确定。我认为这是为遗留代码编写单元测试的问题,我怀疑可能有一种既定的方法来解决这个问题。在这种情况下,我可以更改设计,但是我们有大量的遗留代码可能是不可能的。真的没有办法模拟使用参数化构造函数在方法内部实例化的对象吗?
-
对具体类的依赖通常是为遗留代码创建测试的首要问题。值得庆幸的是,通过注入工厂/提供者模式相对容易对抗。
标签: c# unit-testing nunit moq