1

I am using xUnit tool to write unit test cases in Dot net core. Here in this example, I am also trying to mock protected method of the controller.

public interface ITestService {
    string GetString(string testString);
}

public class TestModel {
    string testValue { get; set; }
}

public class TestController : Controller
{
    readonly ITestService testService;

    public TestController() {
    }

    public TestController(ITestService _testService) {
        testService = _testService;
    }

    [HttpPost]
    public async Task<IActionResult> Post([FromBody]TestModel testModel)
    {
        string test = GetString("testNew");
        await Task.Run(() => "test");
        return Ok(test);
    }

    protected virtual string GetString(string testString)
    {
        return "test" + testString;
    }
}

Therefore, I will need to mock the controller itself to get protected method unit tested in its calling method.

But I am getting Null value when I call controller's method using Mocked object.

public class TestControllerTest
{
    private Mock<ITestService> MockTestService { get; }
    TestController controller { get; }

    public TestControllerTest()
    {
        MockTestService = new Mock<ITestService>();

        controller = new TestController(MockTestService.Object);
    }

    [Fact]
    public void Post_TakesTestString_ReturnsString()
    {
        var MockController = new Mock<TestController>(MockTestService.Object);
        MockController.Protected().Setup<string>("GetString", ItExpr.IsAny<string>()).Returns("testMockValue").Verifiable();

        var result = MockController.Object.Post(new TestModel() { }).Result;
        // result returns NULL value

        MockController.Protected().Verify("GetString", Times.Once(), ItExpr.IsAny<string>());
    }
}

My issue is on below line in code -

var result = MockController.Object.Post(new TestModel() { }).Result;

Which returns Null value, I expect, line should return OkObjectResult with test string.

Nkosi
  • 235,767
  • 35
  • 427
  • 472

1 Answers1

0

As the subject class under test is also being mocked, the actual target method needs to be invoked.

Enable that with CallBase property set to true otherwise the default behavior is to return null for members not setup to be called.

For example

public class TestControllerTest {

    [Fact]
    public async Task Post_TakesTestString_ReturnsString() {
        //Arrange
        var MockTestService = new Mock<ITestService>();
        var MockController = new Mock<TestController>(MockTestService.Object) {
            CallBase = true //<--
        };
        MockController.Protected().Setup<string>("GetString", ItExpr.IsAny<string>()).Returns("testMockValue").Verifiable();
        TestController controller = MockController.Object;

        //Act
        var result = await controller.Post(new TestModel() { });

        //Assert    
        MockController.Protected().Verify("GetString", Times.Once(), ItExpr.IsAny<string>());
    }
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • **Thanks Nikosi..** **CallBase = true** for MockController is now working for me to get expected result. It returns what i expect from the calling method. Only the thing is, i will need to call mockedController's object method to get result as below. **var result = MockSignInController.Object.Post(new ConnectResponse() { }).Result;** – Jitendra Sonawane Aug 22 '19 at 06:30
  • You missed the part where I assign the mocked object to a variable. Reread the provided code. – Nkosi Aug 22 '19 at 09:47
  • Really i had missed the part as you mentioned - MockController.Object. Thanks, thanks a lot for your solution. – Jitendra Sonawane Aug 27 '19 at 12:15