我有一些遗留代码,并针对我对该代码所做的改进编写了测试。我有一个类 SiteSession 并提取了一个接口(interface) ISiteSession 以便可以在调用类中注入(inject)依赖项。
public class SiteSession : ISiteSession
{
public SiteSession(string userName, string externalRef, IePermitProAdapterClient ePermitService)
{
//.......
}
//...
}
调用类有一个构造函数,其中依赖项被注入(inject)到正在测试的 Controller 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);
//.....
//...
//...
}
现在我的测试方法已经模拟了依赖关系,我对为此 Controller 或代码的任何其他部分创建的任何测试都没有问题。但是当调用这个 Controller
CustomerDetails
上的测试时,实际的构造函数调用是对 SiteSession
类进行的,我无法注入(inject)模拟并中断真正的调用。我的测试代码如下: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
最佳答案
这是一个设计问题。通过在 Controller 中手动创建实例, Controller 与实现紧密耦合,这使得模拟变得非常困难。查看您的设计选择,因为当前示例在最终目标方面不是很清楚。
提供适当单元测试的难度应该是设计问题的直接指标。
话虽如此,根据当前的设计,如果您可以控制 Controller ,则可能需要 session 提供程序
public interface ISiteSessionProvider {
ISiteSession CreateSiteSession(CustomerDetails customerDetails);
}
Controller 将明确依赖于哪个
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);
}
关于c# - 如何模拟在被测方法内实例化的对象,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50465386/