使用UnityAutoMoq解析采用构造函数参数的接口,对MVC控制器进行单元测试



正如标题所说,我正试图解析一个接口,该接口实现了一个也需要构造函数的具体类。

下面是一个具体的服务类示例:

public class MessageService : IMessageService
{
private readonly IMessageGenerator _messageGenerator;
public MessageService(IMessageGenerator messageGenerator)
{
_messageGenerator = messageGenerator;
}
public string GetMessage()
{
return string.Concat(_messageGenerator.GetMessage(), "");
}
}

正如您所看到的,这个服务类还需要一个接口作为构造函数参数。MVC控制器构造函数如下所示:

private readonly IMessageService _messageSvc;
public HomeController(IMessageService messageSvc)
{
_messageSvc = messageSvc;
}

多亏了Unity.Mvc3 ,我在引导程序中解决了接口问题

var container = new UnityContainer();
container
.RegisterType<IMessageService, MessageService>()
.RegisterType<IMessageGenerator, MessageGenerator>();

因此,我遇到的主要问题是,如何在单元测试中使用UnityAutoMoq将IMessageGenerator接口的模拟实例传递给IMessageService?我认为这样的东西会起作用,但事实并非如此:

[TestMethod]
public void Index()
{
var container = new UnityAutoMoqContainer();
var controllerContext = container.Resolve<ControllerContext>();
var nMsgSvc = container.Resolve<IMessageService>(container.Resolve<IMessageGenerator>);
var sut = new HomeController(nMsgSvc) { ControllerContext = controllerContext };
ViewResult result = sut.Index() as ViewResult;
Assert.AreEqual("Hello from the MessageGenerator via the MessageService", result.ViewBag.Message);
}

在测试控制器时不需要这样做。在这种情况下,控制器只需要IMessageService的一个mock。

此外,为了测试Index方法,我根本不会使用容器,因为它不涉及。

应该这样做:

// arrange
var messageService = new Mock<IMessageService>();
// setup message service
...
var controller = new HomeController(messageService.Object);
// act
...

这个问题是很久以前问过的。但我会提供一个可能有帮助的答案。您真的不想截断IMessageGenerator。您想要的是截取IMessageService。并将其配置为返回所需的消息。IMessageGenerator返回的内容与您的控制器无关。只有当您在控制器中使用IMessageGenerator时,它才会成为一个问题。

请注意,使用UnityAutoMoq容器也不能很好地编写测试。

您可以将IMessageService配置为返回所需的字符串,如下所示。

[TestMethod]
public void Index_ViewData_ContainsExpectedMessage()
{
var container = new UnityAutoMoqContainer();
var messageToReturnViaMessageGenerator = "Hello from the MessageGenerator via the MessageService";                        
var messageGenratorStub = container.GetMock<IMessageService>();
messageGenratorStub.Setup(x => x.GetMessage()).Returns(messageToReturnViaMessageGenerator);
var sut = container.Resolve<HomeController>();
ViewResult result = sut.Index() as ViewResult;
Assert.AreEqual(messageToReturnViaMessageGenerator, result.ViewBag.Message);
}

需要注意的事情很少

  • 您不需要解析ControllerContext-对于本测试而言,这是不必要的
  • 正在解决Sut。。。

    var sut = container.Resolve<HomeController>();
    

这将返回您的sut(测试中的系统)。此实例还可以包含您使用UnityAutoMoqContainer存根的任何存根实例。在这种情况下,它是存根IMessageService。这样,您就不必显式地将存根IMessageService实例传递给Controller的构造函数。

  • 只是一个次要的-总是给出一个可读的测试名称;)

HTH

最新更新