Using Moq to test methods that accept non-primative arguments

心不动则不痛 提交于 2020-01-05 08:28:12

问题


I'm trying to write a test for an ASP.Net MVC controller action.

I'd like to test that the action invokes a particular method on an injected service, so I'm mocking the service and using .Verify.

So in the simple case, I have the following action in my controller:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(string title)
    {
        _cmsService.AddPage(title);

        return View("Edit");
    }

using the service interface...

public interface ICmsService
{
    void AddPage(string request);
}

and the following test...

        //Arrange
        const string pageTitle = "Test Page";

        var cmsService = new Mock<ICmsService>();

        cmsService.Setup(service => service.AddPage(pageTitle));

        var controller = new PageController(cmsService.Object);

        //Act
        var result = controller.Create(pageTitle) as ViewResult;

        //Assert
        cmsService.Verify(service => service.AddPage(pageTitle), Times.Once());

Now I want to refactor my service operation to use request and response objects...

public interface ICmsService
{
    CmsServiceAddPageResponse AddPage(CmsServiceAddPageRequest request);
}

So I change my action accordingly...

    public ActionResult Create(string title)
    {
        var request = new CmsServiceAddPageRequest()
                          {
                              PageName = title
                          };

        var response = _cmsService.AddPage(request);

        return View("Edit");
    }

and also my test...

        //Arrange
        const string pageTitle = "Test Page";

        var cmsService = new Mock<ICmsService>();

        var request = new CmsServiceAddPageRequest() {PageName = pageTitle};

        cmsService.Setup(service => service.AddPage(request));

        var controller = new PageController(cmsService.Object);

        //Act
        var result = controller.Create(pageTitle) as ViewResult;

        //Assert
        cmsService.Verify(service => service.AddPage(request), Times.Once());

But now when I run the test, I get the following message...

TestCase 'Web.Test.PageControllerTest.CreateNewPagePost'
failed: Moq.MockException : 
Invocation was performed more than once on the mock: service => service.AddPage(value(Web.Test.PageControllerTest+<>c__DisplayClass1).request)
    at Moq.Mock.ThrowVerifyException(IProxyCall expected, Expression expression, Times times)
    at Moq.Mock.VerifyCalls(Interceptor targetInterceptor, MethodCall expected, Expression expression, Times times)
    at Moq.Mock.Verify[T,TResult](Mock mock, Expression`1 expression, Times times, String failMessage)
    at Moq.Mock`1.Verify[TResult](Expression`1 expression, Times times)
    PageControllerTest.cs(67,0): at Web.Test.PageControllerTest.CreateNewPagePost()

What should I be doing to test a method that accepts a non-primitive type?

Thanks

Sandy


回答1:


I think a better alternative to the first answer would be to implement a custom matcher rather than change code to match your testing framework. From:http://code.google.com/p/moq/wiki/QuickStart

// custom matchers
mock.Setup(foo => foo.Submit(IsLarge())).Throws<ArgumentException>();
...
public string IsLarge() 
{ 
  return Match<string>.Create(s => !String.IsNullOrEmpty(s) && s.Length > 100);
}



回答2:


If you override Equals in the CmsServiceAddPageRequest object it should compare them correctly.



来源:https://stackoverflow.com/questions/2245710/using-moq-to-test-methods-that-accept-non-primative-arguments

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!