2

I am working in a .Net Core API. I wish to unit test the GetArtists method on the ArtistsController.

CODE

Here is my controller code:

[Route("artists")]
public class ArtistsController : Controller
{
  private readonly IPermissionsService _permissionsService;
  private readonly IArtistsService _artistsService;
  private readonly ILogger<ArtistsController> _logger;

  public ArtistsController(IPermissionsService permissionsService, IArtistsService artistsService, ILogger<ArtistsController> logger)
  {
    _permissionsService = permissionsService ?? throw new ArgumentNullException(nameof(permissionsService));
    _artistsService = artistsService ?? throw new ArgumentNullException(nameof(artistsService));
    _logger = logger ?? throw new ArgumentNullException(nameof(logger));
  }

  [HttpGet]
  public async Task<IActionResult> GetArtists()
  {
    var permissions = await _permissionsService.GetPermissionsAsync(HttpContext);
    var artists = _artistsService.GetAllArtists(permissions.UserId, permissions.IsAdministrator);
    return Ok( new { artists });
  }
}

And here is the test method I am writing:

[TestClass]
public class ArtistsControllerTests
{
  private readonly Mock<IPermissionsService> _mockPermissionsService = new Mock<IPermissionsService>();
  private readonly Mock<IArtistsService> _mockArtistsService = new Mock<IArtistsService>();
  private readonly Mock<ILogger<ArtistsController>> _mockLogger = new Mock<ILogger<ArtistsController>>();

  public void Setup()
  {
    _mockArtistsService.Reset();
    _mockPermissionsService
      .Setup(service => service.GetPermissionsAsync(It.IsAny<HttpContext>()))
      .Returns(Task.FromResult(new Permissions { UserId = "112233", IsAdministrator = false }));
    _mockArtistsService.Setup(service => service.GetAllArtists(It.IsAny<string>(), false)).Returns(new ArtistCardDtoCollection());
  }

  [TestMethod]
  public async Task GetArtists_ReturnsOKStatusCode()
  {
    // arrange
    var artistsController = new ArtistsController(_mockPermissionsService.Object, _mockArtistsService.Object, _mockLogger.Object);
    // act
    var getArtistsResult = await artistsController.GetArtists();
    var okResult = getArtistsResult as OkObjectResult;
    // assert
    Assert.IsInstanceOfType(okResult, typeof(OkObjectResult));
  }
}

Here is the IPermissionsService and the Permissions class.

public interface IPermissionsService
{
  Task<Permissions> GetPermissionsAsync(HttpContext httpContext);
}

public class Permissions
{
  public string UserId { get; set; }
  public bool IsAdministrator { get; set; }
}

When I run that, I get the following error:

Project.ArtistsControllerTests.GetArtists_ReturnsOKStatusCode threw exception: System.NullReferenceException: Object reference not set to an instance of an object.

When debugging, I found out that var permissions = await _permissionsService.GetPermissionsAsync(HttpContext); returns null.

I must have an issue with the way I am mocking that:

_mockPermissionsService
    .Setup(service => service.GetPermissionsAsync(It.IsAny<HttpContext>()))

Why wouldn't the above work?

Nkosi
  • 191,971
  • 29
  • 311
  • 378
J86
  • 11,751
  • 29
  • 115
  • 194
  • can you check which variable returns null? – Neville Nazerane Sep 18 '17 at 10:20
  • 3
    Don't run your test and put the results here; debug it yourself. Something is null. – CodeCaster Sep 18 '17 at 10:20
  • Sorry, I did try to debug @CodeCaster, I forgot to add that info, my apologies. – J86 Sep 18 '17 at 10:38
  • Added a screencast to show what is happening. – J86 Sep 18 '17 at 10:46
  • @Ciwan put a break point in the `GetArtists` and step through there. Possibility may be that you did not configure one of the mock correctly – Nkosi Sep 18 '17 at 10:55
  • @Nkosi I'm so stupid sometimes, sorry. Found out the issue, and updated the question. – J86 Sep 18 '17 at 12:01
  • @Ciwan show the `IPermissionsService` interface definition. – Nkosi Sep 18 '17 at 12:10
  • I've updated the question to add that code. – J86 Sep 18 '17 at 12:12
  • @Ciwan Ok figured it out. Your `ArtistsControllerTests.Setup()` is not being invoked so the mocks are not being setup. Therefore when the test is exercised they will return null. Your setup code is correct, it just is not getting called. – Nkosi Sep 18 '17 at 12:13
  • @Ciwan either change that method to a constructor or adorn the method with `[TestInitilize]` attribute or just move the arrange into the test itself – Nkosi Sep 18 '17 at 12:16
  • Damn, so it was more stupidity on my part. Sorry, I should have spotted that. Please reply as an answer so that I may mark the question as answered. :) – J86 Sep 18 '17 at 12:19

1 Answers1

2

ArtistsControllerTests.Setup() is not being invoked so the mocks are not being setup before the test is exercised.

Therefore when the test is exercised they will return null.

Your setup code is correct, it just is not getting called.

either change that Setup method to a constructor

public ArtistsControllerTests() {
    _mockArtistsService.Reset();
    _mockPermissionsService
      .Setup(service => service.GetPermissionsAsync(It.IsAny<HttpContext>()))
      .Returns(Task.FromResult(new Permissions { UserId = "112233", IsAdministrator = false }));
    _mockArtistsService.Setup(service => service.GetAllArtists(It.IsAny<string>(), false)).Returns(new ArtistCardDtoCollection());
}

or adorn the method with [TestInitilize] attribute

[TestInitialize]
public void Setup() {
    _mockArtistsService.Reset();
    _mockPermissionsService
      .Setup(service => service.GetPermissionsAsync(It.IsAny<HttpContext>()))
      .Returns(Task.FromResult(new Permissions { UserId = "112233", IsAdministrator = false }));
    _mockArtistsService.Setup(service => service.GetAllArtists(It.IsAny<string>(), false)).Returns(new ArtistCardDtoCollection());
}

or just move the arrange into the test itself

[TestMethod]
public async Task GetArtists_ReturnsOKStatusCode() {
    // arrange
    _mockArtistsService.Reset();
    _mockPermissionsService
      .Setup(service => service.GetPermissionsAsync(It.IsAny<HttpContext>()))
      .Returns(Task.FromResult(new Permissions { UserId = "112233", IsAdministrator = false }));
    _mockArtistsService.Setup(service => service.GetAllArtists(It.IsAny<string>(), false)).Returns(new ArtistCardDtoCollection());
    var artistsController = new ArtistsController(_mockPermissionsService.Object, _mockArtistsService.Object, _mockLogger.Object);
    // act
    var getArtistsResult = await artistsController.GetArtists();
    var okResult = getArtistsResult as OkObjectResult;
    // assert
    Assert.IsInstanceOfType(okResult, typeof(OkObjectResult));
}
Nkosi
  • 191,971
  • 29
  • 311
  • 378