模拟了一个方法 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,我建议也断言这一点。 (就像我在上面的测试用例中所做的那样)