模拟了一个方法 return true 还是 returns false
Mocked a method to return true still returns false
我有一个这样的控制器方法:
public class ValuesController : Controller
{
private readonly IService fService;
public ValuesController( IService fService)
{
this.fService = fService;
}
public IActionResult InsertDetails( [FromForm]Details details, IFormFile file)
{
bool result = fService.SaveDetails(details, file);
return OK();
}
}
测试这个控制器的测试用例如下:
public class ValuesControllerTests
{
readonly Mock<IService> mockService = new Mock<IService>();
[TestMethod]
public void SaveDetails_Test_Success()
{
var details = GetMockDetails(); // gets the sample DTO values
mockService.Setup(x => x.SaveDetails(details, GetFile())).Returns(true); ---- this is returning false even after mocking the value
var controller = new ValuesController(mockService.Object);
controller.ControllerContext.HttpContext = new DefaultHttpContext();
var res = controller.InsertDetails(details, GetFile()) as OkObjectResult;
Assert.AreEqual("File Details Saved Successfully", res.Value.ToString());
Assert.AreEqual(200, res.StatusCode);
}
IFormFile GetFile()
{
return new FormFile(new MemoryStream(Encoding.UTF8.GetBytes("This is a dummy file")), 0, 0, "Data", "dummy.txt");
}
}
即使我将方法 SaveDetails
模拟为 return true
,它总是 returns false
.
谁能告诉我我在这里做错了什么?非常感谢。
预期的设置 IFormFile
(reference/instance) 不同于调用被测成员时使用的预期。这会导致模拟 return 被调用成员的默认值,即 false
因为它是布尔值。
当 GetFile()
被调用时,它每次 return 都是一个新实例。
所以要么使用同一个实例,就像 details
public void SaveDetails_Test_Success() {
Details details = GetMockDetails();
IFormFile file = GetFile(); //single instance
mockService.Setup(x => x.SaveDetails(details, file)).Returns(true); //used here
ValuesController controller = new ValuesController(mockService.Object);
controller.ControllerContext.HttpContext = new DefaultHttpContext();
var res = controller.InsertDetails(details, file) as OkObjectResult; //and here
Assert.AreEqual("File Details Saved Successfully", res.Value.ToString());
Assert.AreEqual(200, res.StatusCode);
}
或者使用像 It.IsAny<>()
这样的参数匹配器来放松期望
public void SaveDetails_Test_Success() {
Details details = GetMockDetails();
mockService.Setup(x => x.SaveDetails(details, It.IsAny<IFormFile>())).Returns(true); //<-- NOTE
ValuesController controller = new ValuesController(mockService.Object);
controller.ControllerContext.HttpContext = new DefaultHttpContext();
var res = controller.InsertDetails(details, GetFile()) as OkObjectResult;
Assert.AreEqual("File Details Saved Successfully", res.Value.ToString());
Assert.AreEqual(200, res.StatusCode);
}
你的 Setup
的问题是它太具体了。
请记住,在 类.
的情况下,参数匹配基于参考检查
mockService
.Setup(service => service.SaveDetails(It.IsAny<Details>(), It.IsAny<IFormFile>()))
.Returns(true);
如果您想验证来电,则需要
保存 GetFile
的结果,然后进行断言:
public void SaveDetails_Test_Success()
{
//Arrange
var details = GetMockDetails();
var file = GetFile(); //same instance is used everywhere
mockService
.Setup(x => x.SaveDetails(It.IsAny<Details>(), It.IsAny<IFormFile>()))
.Returns(true);
var controller = new ValuesController(mockService.Object);
controller.ControllerContext.HttpContext = new DefaultHttpContext();
//Act
var result = controller.InsertDetails(details, file);
//Assert
var res = Assert.IsAssignableForm<OkObjectResult>(result); //Here we test the assignability as well
Assert.AreEqual("File Details Saved Successfully", res.Value.ToString());
//Assert.AreEqual(200, res.StatusCode); //This assert is unnecessary
mockService
.Verify(x => x.SaveDetails(details, file), Times.Once);
}
与其将控制器操作的响应强制转换为 OkObjectResult
,我建议也断言这一点。 (就像我在上面的测试用例中所做的那样)
我有一个这样的控制器方法:
public class ValuesController : Controller
{
private readonly IService fService;
public ValuesController( IService fService)
{
this.fService = fService;
}
public IActionResult InsertDetails( [FromForm]Details details, IFormFile file)
{
bool result = fService.SaveDetails(details, file);
return OK();
}
}
测试这个控制器的测试用例如下:
public class ValuesControllerTests
{
readonly Mock<IService> mockService = new Mock<IService>();
[TestMethod]
public void SaveDetails_Test_Success()
{
var details = GetMockDetails(); // gets the sample DTO values
mockService.Setup(x => x.SaveDetails(details, GetFile())).Returns(true); ---- this is returning false even after mocking the value
var controller = new ValuesController(mockService.Object);
controller.ControllerContext.HttpContext = new DefaultHttpContext();
var res = controller.InsertDetails(details, GetFile()) as OkObjectResult;
Assert.AreEqual("File Details Saved Successfully", res.Value.ToString());
Assert.AreEqual(200, res.StatusCode);
}
IFormFile GetFile()
{
return new FormFile(new MemoryStream(Encoding.UTF8.GetBytes("This is a dummy file")), 0, 0, "Data", "dummy.txt");
}
}
即使我将方法 SaveDetails
模拟为 return true
,它总是 returns false
.
谁能告诉我我在这里做错了什么?非常感谢。
预期的设置 IFormFile
(reference/instance) 不同于调用被测成员时使用的预期。这会导致模拟 return 被调用成员的默认值,即 false
因为它是布尔值。
当 GetFile()
被调用时,它每次 return 都是一个新实例。
所以要么使用同一个实例,就像 details
public void SaveDetails_Test_Success() {
Details details = GetMockDetails();
IFormFile file = GetFile(); //single instance
mockService.Setup(x => x.SaveDetails(details, file)).Returns(true); //used here
ValuesController controller = new ValuesController(mockService.Object);
controller.ControllerContext.HttpContext = new DefaultHttpContext();
var res = controller.InsertDetails(details, file) as OkObjectResult; //and here
Assert.AreEqual("File Details Saved Successfully", res.Value.ToString());
Assert.AreEqual(200, res.StatusCode);
}
或者使用像 It.IsAny<>()
public void SaveDetails_Test_Success() {
Details details = GetMockDetails();
mockService.Setup(x => x.SaveDetails(details, It.IsAny<IFormFile>())).Returns(true); //<-- NOTE
ValuesController controller = new ValuesController(mockService.Object);
controller.ControllerContext.HttpContext = new DefaultHttpContext();
var res = controller.InsertDetails(details, GetFile()) as OkObjectResult;
Assert.AreEqual("File Details Saved Successfully", res.Value.ToString());
Assert.AreEqual(200, res.StatusCode);
}
你的 Setup
的问题是它太具体了。
请记住,在 类.
mockService
.Setup(service => service.SaveDetails(It.IsAny<Details>(), It.IsAny<IFormFile>()))
.Returns(true);
如果您想验证来电,则需要
保存 GetFile
的结果,然后进行断言:
public void SaveDetails_Test_Success()
{
//Arrange
var details = GetMockDetails();
var file = GetFile(); //same instance is used everywhere
mockService
.Setup(x => x.SaveDetails(It.IsAny<Details>(), It.IsAny<IFormFile>()))
.Returns(true);
var controller = new ValuesController(mockService.Object);
controller.ControllerContext.HttpContext = new DefaultHttpContext();
//Act
var result = controller.InsertDetails(details, file);
//Assert
var res = Assert.IsAssignableForm<OkObjectResult>(result); //Here we test the assignability as well
Assert.AreEqual("File Details Saved Successfully", res.Value.ToString());
//Assert.AreEqual(200, res.StatusCode); //This assert is unnecessary
mockService
.Verify(x => x.SaveDetails(details, file), Times.Once);
}
与其将控制器操作的响应强制转换为 OkObjectResult
,我建议也断言这一点。 (就像我在上面的测试用例中所做的那样)