如何模拟在测试方法中实例化的对象



我有一些遗留代码,并编写了关于我对该代码所做的增强的测试。我有一个类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

这是一个设计问题。通过在控制器中手动创建实例,控制器与实现紧密耦合,这使得模拟变得非常困难。查看您的设计选择,因为当前示例在最终目标方面不是很清楚。

提供适当的单元测试的困难应该是设计问题的直接指标。

话虽如此,基于当前的设计,并且如果您控制控制器,则可能需要会话提供程序

public interface ISiteSessionProvider {
ISiteSession CreateSiteSession(CustomerDetails customerDetails);
}

控制器将明确依赖哪个

public class SsoController: Controller {
private readonly ICustomerDetails _customerDetails;
private readonly ISiteSessionProvider siteSessionProvider;
public SsoController(ICustomerDetails customerDetails, ISiteSessionProvider siteSessionProvider) {
_customerDetails = customerDetails;
this.siteSessionProvider = siteSessionProvider;
}
public ActionResult CustomerDetails(CustomerDetails customerDetails) {
//...
ISiteSession siteSession = siteSessionProvider.CreateSiteSession(customerDetails);
//...
}
}

单元测试现在需要您模拟所需的行为

//Arrange
var sessionMock = new Mock<ISiteSession>();
sessionMock.Setup(_ => _.Token).Returns("TestToken");
var providerMock = new Mock<ISiteSessionProvider>();
providerMock
.Setup(_ => _.CreateSiteSession(It.IsAny<CustomerDetails>()))
.Returns(sessionMock.Object);
var controller = new SsoController(Mock.Of<ICustomerDetails>(), providerMock.Object);
//Act
var result = controller.CustomerDetails(...);
//Assert
//...

然后,提供程序的实现可以处理实现问题

public ISiteSession CreateSiteSession(CustomerDetails customerDetails) {
//...
return new SiteSession(customer.Username, customer.CustomerRef, ePermitService);
}

最新更新