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

时间:2018-05-22 10:25:50

标签: c# unit-testing nunit moq

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

1 个答案:

答案 0 :(得分:4)

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

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

话虽如此,基于当前的设计,如果您控制了控制器,您可能需要会话提供商

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);
}