我对使用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参数设置方法。我对你的代码做了两个更正,它工作了。
- 您必须在模拟设置和执行套件时使用相同的候选实例。否则,Moq认为这两个对象是不同的,并且您的测试设置变得无用。
-
你不需要使用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的快速入门,了解它的功能。