Unit testing a Web API controller

28,958

You need to configure the setup to expect a particular behavior or argument for the test.

In this case using the It.IsAny<T>() to tell the set up what to expect in terms of arguments will allow the test to flow as desired.

Given that the GetAll method requires two parameters of Func<IQueryable<T>, IOrderedQueryable<T>> and string, the setup configures what to do based on the values entered for those parameters.

[Test]
public async Task Get_ReturnsAAListOfBrands() {
    //Arrange
    var mockService = new Mock<IGenericService<Brand>>();
    mockService
        .Setup(repo => repo.GetAll(It.IsAny<Func<IQueryable<Brand>, IOrderedQueryable<Brand>>>(), It.IsAny<string>()))
        .ReturnsAsync(Brands);
    var controller = new BrandsController(mockService.Object);

    //Act
    var result = await controller.Get();
    //Assert
    //...
}

Take a look at the Moq Quickstart for a better understanding of how to use this mocking framework

Share:
28,958
JMon
Author by

JMon

Updated on July 09, 2022

Comments

  • JMon
    JMon almost 2 years

    I am fairly new to unit testing and I am trying to create a unit test for a Web API contoller that I have created which returns a list of brands.

    My Web API controller Get() method looks like this:

    [HttpGet("/api/Brands/Get", Name = "GetBrands")]
    public async Task<IActionResult> Get()
    {
        var brands = await _brandsService.GetAll(null, "Image");
        return Json(brands);
    }
    

    The generic service method looks like this:

    public async Task<List<T>> GetAll(
        Func<IQueryable<T>, 
        IOrderedQueryable<T>> orderBy = null, 
        string includeProperties = null)
    {
        return await _genericRepository.GetAll(orderBy, includeProperties);
    }
    

    and the generic repo method looks like this:

    public async Task<T> Get<TKey>(Expression<Func<T, bool>> filter = null, string includeProperties = "", bool noTracking = false)
    
    {
        includeProperties = includeProperties.Trim() ?? string.Empty;
        IQueryable<T> query = Context.Set<T>();
    
        if (noTracking)
        {
            query.AsNoTracking();
        }
    
        if (filter != null)
        {
            query = query.Where(filter);
        }
    
        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }
    
        return await query.SingleOrDefaultAsync();
    }
    

    This is working and I am returning a list of brands from the database.

    Now I tried to create a Unit test for this:

    [SetUp]
    public void Setup()
    {
        Brands = new List<Brand>
        {
            new Brand
            {
                Id = 1,
                Name = "Adidas",
                ImageId = 1
            },
            new Brand
            {
                Id = 2,
                Name = "Nike",
                ImageId = 2
            },
            new Brand
            {
                Id = 3,
                Name = "Puma",
                ImageId = 3
            }
        };
    }
    
    [Test]
    public async Task Get_ReturnsAAListOfBrands()
    {
        //Arrange
        var mockService = new Mock<IGenericService<Brand>>();
        mockService.Setup(repo => repo.GetAll(null, null)).Returns(Task.FromResult(Brands));
        var controller = new BrandsController(mockService.Object);
    
        //Act
        var result = await controller.Get();
        //Assert
    }
    

    however the result is always null. Am I testing this correctly or do I need to change my unit test code to verify that the mock service has three items stored?

  • JMon
    JMon over 7 years
    just as I was going to type that I had solved it, saw your code here :) Thanks will add this as the anwer!
  • JMon
    JMon over 7 years
    yes I have to investigate mocking better, that is why I am doing some examples. Thanks for your help
  • JMon
    JMon over 7 years
    This example helped me a lot to come to the answer stackoverflow.com/questions/35565353/…
  • JMon
    JMon over 7 years
    just one last thing, how can I verify that the result.Count() is actually 3? My JsonResult does not seem to allow me to see the Data, and I cannot get the Count() from the Value:- JsonResult actualResult = await controller.Get() as JsonResult; var data = actualResult.Data;
  • Nkosi
    Nkosi over 7 years
    Now it is a little tricky. This is however not the first time I've encountered this. check my answer here and see if it applies to your situation.