单元测试- Moq out参数



我对使用Moq和Nunit进行单元测试相当陌生,我在一个场景中遇到了问题。我想要的是我的mock有一个out参数,然后我的被测系统将使用它来决定采取什么行动。

我的系统在测试是一个MVC API控制器,特别是我试图测试POST方法。当验证失败时,我想为对象返回一个错误消息。

下面是控制器的方法代码:

        public IHttpActionResult Post(Candidate candidate)
    {
        try
        {
            if(candidate==null)
                return BadRequest();
            IEnumerable<string> errors;
            _candidateManager.InsertCandidate(candidate, out errors);
            if (errors!=null && errors.Any())
                return BadRequest(CreateErrorMessage("Invalid candidate: ", errors));
            return CreatedAtRoute("DefaultApi", new {id = candidate.CandidateId}, candidate);
        }
        catch (Exception)
        {
            return InternalServerError();
        }
    }
这是我的单元测试代码:
        [Test]
    [Category("CandidateManagerController Unit Tests")]
    public void Should_Return_Bad_Request_When_Creating_Invalid_Candidate()
    {
        IEnumerable<string> errors = new List<string>() {"error1", "error2"};
        var mockManager = new Mock<ICandidateManager>();
        mockManager.Setup(x => x.InsertCandidate(new Candidate(), out errors)).Callback(()=>GetErrors(errors));
        var sut = new CandidateManagerController(mockManager.Object);
        var actionResult = sut.Post(new Candidate());
        Assert.IsInstanceOf<BadRequestResult>(actionResult);
    }

我期望的是当_candidateManager.InsertCandidate()运行时,然后填充errors变量。然而,正在发生的事情是,当您通过控制器代码步进错误是空的_candidateManager.InsertCandidate()方法运行后。

如果有人知道我做错了什么,或者如果我想做的是不可能使用Moq,那么请让我知道。

谢谢

你想做的是可能的。如果您查看https://github.com/Moq/moq4/wiki/Quickstart上的快速入门文档,其中有一节展示了如何使用out参数设置方法。我对你的代码做了两个更正,它工作了。

  1. 您必须在模拟设置和执行套件时使用相同的候选实例。否则,Moq认为这两个对象是不同的,并且您的测试设置变得无用。
  2. 你不需要使用Callback来设置被模拟的CandidateManager返回的错误。下面是我修改后的测试方法。

    [Test]
    [Category("CandidateManagerController Unit Tests")]
    public void Should_Return_Bad_Request_When_Creating_Invalid_Candidate()
     {
    IEnumerable<string> errors = new List<string>() {"error1", "error2"};
    //instance to be used for both setup and test later
    var candidate = new Candidate(); 
    var mockManager = new Mock<ICandidateManager>();
    //removed Callback
    mockManager.Setup(x => x.InsertCandidate(candidate, out errors));
    var sut = new CandidateManagerController(mockManager.Object);
    var actionResult = sut.Post(candidate);
    Assert.IsInstanceOf<BadRequestResult>(actionResult);
     }
    

您必须确保在调用SUT时使用传递给out参数的相同实例,否则调用将失败。

在您的示例中,被测试的方法将一个空实例传递给被模拟的方法,从而使测试的设置无效。

但是,如果您不能为out提供相同的实例,那么看起来您将无法使模拟成功通过。看看Moq的快速入门,了解它的功能。

最新更新