Search code examples
c#mockingasp.net-core-webapimoqvs-unit-testing-framework

Mocked a method to return true still returns false


I have a controller method like this :

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();
    }
}

The test case to test this controller is as below:

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");
     }
}

Even though I mocked the method SaveDetails to return true, it always returns false.
Can anyone tell me what am I doing wrong here? Many thanks.


Solution

  • The expectation was setup with a different IFormFile (reference/instance) than the one that was used when invoking the member under test. This causes the mock to return the default value of the invoked member, which is false since it is a boolean.

    When GetFile() is invoked, it returns a new instance every time.

    So either use the same instance, like was done with 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);
     }
    

    Or loosen up the expectation using argument matchers like 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);
     }