I am writing the unit test for method inside which calls internal method. How can we mock the internal method?

Viewed 39

Here is my code:

public IActionResult Post([FromBody] ApiPermission apiClient)
{
    return Ok(_apiPermissionService.Add(apiClient, GetCurrentUserFullName(_httpContextAccessor.HttpContext.User)));
}

I need the result of GetCurrentUserFullName which has the definition of

internal string GetCurrentUserFullName(ClaimsPrincipal principal)
{
    if (principal == null)
        throw new ArgumentNullException(nameof(principal));

    return principal.FindFirstValue("UserFullName");
}

How we can pass GetCurrentUserFullName to pass the test.

Below is my testing code:

 public void Post()
{
    Mock<ApiPermissionGroup> mockApiPermissionGroup = new Mock<ApiPermissionGroup>();
    var apiPermission = new ApiPermission
    {
        ApiPermissionId = 1,
        Name = "Name",
        Description = "Description",
        AddedBy = "AddedBy",
        AddedDate = DateTime.UtcNow,
        ModifiedBy = "ModifiedBy",
        ModifiedDate = DateTime.UtcNow,
        ApiPermissionGroupId = 2,
        ApiPermissionGroup = mockApiPermissionGroup.Object
    };
    List<ApiPermission> lstApiPermission = new List<ApiPermission>();
    lstApiPermission.Add(apiPermission);

    ApiPermissionController ApiPermissionController = new ApiPermissionController(_mockApiPermissionService.Object, _mockHttpContextAccessor.Object);

    var result = ApiPermissionController.Post(apiPermission);
    Assert.IsNotNull(result);
}

When running the above code I am getting the error " System.NullReferenceException : Object reference not set to an instance of an object." at

Microsoft.AspNetCore.Http.IHttpContextAccessor.HttpContext.get returned null.

1 Answers

In this specific case, I'd not mock the internal method, but mock the context accessor, e.g.:

// Set up mock principal
var principal = new Mock<ClaimsPrincipal>();
principal
  .Setup(r => r.FindFirst("UserFullName"))
  .Returns(new Claim("UserFullName", "TEST_USER_NAME"));
// Create dummy context
var context = new DefaultHttpContext { User = principal.Object };
// Set up mock context accessor
var mockCtxAcc = new Mock<IHttpContextAccessor>();
mockCtxAcc.SetupGet(x => x.HttpContext).Returns(context);
// Create controller under test
var ctrl = new MyController(mockCtxAcc.Object, ...);

The unit test should test the behavior of the class as it is, but without the dependencies of the class. This way, you test the code that the controller runs in real life scenario - also the internal method as it is.

Related