Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing with Generic Repository in .net Core

I'm building a test project to fiddle around with .net core and I'm hitting a snag of some sorts. The basic idea of the toying around is adding products to the context, no biggie right. Well wrong. Because I was raised as a good programmer I always start off from the TDD way to go. So I tried the following test.

[Fact]
public async Task AddProduct_ReturnCreatedWithProduct()
{
    Product testProduct = ProductHelpers.GenerateTestProduct();
    var mockRepo = new Mock<IRepository<Product>>();
    mockRepo.Setup(repo => repo.Get(testProduct.ProductID)).Returns(Task.FromResult(testProduct));
    var controller = new ProductController(mockRepo.Object);

    var result = await controller.Post(new ProductViewModel() { ProductID = 1, ProductShortDesc = PRODUCT_SHORTDESC, ProductDescription = PRODUCT_DESC });
    var okResult = Assert.IsType<OkObjectResult>(result);
    var returnProduct = Assert.IsType<Product>(okResult.Value);
    Assert.Equal(testProduct.ProductShortDesc, returnProduct.ProductShortDesc);
    Assert.Equal(testProduct.ProductDescription, returnProduct.ProductDescription);
}

public static Product GenerateTestProduct()
{
    return new Product()
    {
        ProductID = 1,
        ProductShortDesc = "FRI",
        ProductDescription = "Fristi"
    };
}

Which should return a decent OkObjectResult. Well no it doesn't. So I went deep diving in to the controller which gave me this.

[HttpPost]
public async Task<ActionResult> Post([FromBody]ProductViewModel model)
{
    if (!ModelState.IsValid)
        return BadRequest(ModelState);
    else
    {
        var product = await _productRepository.AddEntity(model.ToEntity());
        if (product == null)
            return StatusCode(500);
        else
            return Ok(product);
    }
}

public interface IRepository<T>
{
    Task<T> Get<TKey>(TKey id);
    IQueryable<T> GetAll();
    Task<T> AddEntity(T entity);
    Task DeleteEntity(T entity);
    Task Update(T entity);
}

public class ProductRepository : IRepository<Product>
{
    protected readonly DbContext Context;
    protected DbSet<Product> DbSet;

    public ProductRepository(ApplicationContext context)
    {
        Context = context;
        DbSet = context.Set<Product>();
    }

    public async Task<Product> AddEntity(Product entity)
    {
        try
        {
            await Context.Set<Product>().AddAsync(entity);
            await Save();
            return await Get(entity.ProductID);
        }
        catch (System.Exception ex)
        {
            Debug.WriteLine(ex.Message);
            throw ex;
        }
    }
    //Rest left out for shortness off this post
}

So running the code via postman gave me the following result: enter image description here

So going back to the test because I thought, yes it works somehow now.. enter image description here

[HttpPost]
public async Task<ActionResult> Post([FromBody]ProductViewModel model)
{
    if (!ModelState.IsValid)
        return BadRequest(ModelState);
    else
    {
        var product = await _productRepository.AddEntity(model.ToEntity());
        if (product == null)
            return StatusCode(500);
        else
            return Ok(product);
    }
}

So that didn't go well either. I tried debugging the code to find the root cause but for some reason its not letting me step through in the interface code to find out why the Add doesn't work on my unit test, but does work on the normal postman test. (Just My Code is disabled). Hopefully some of you can help me out with this

like image 983
Nicolas Pierre Avatar asked Oct 30 '22 13:10

Nicolas Pierre


1 Answers

The wrong method is being mocked for the test. The method under test is only interacting with AddEntity so that is the dependency that should be mocked for this test.

mockRepo
    .Setup(repo => repo.AddEntity(It.Is<Product>(vm => 
            vm.ProductShortDesc == testProduct.ProductShortDesc 
            && vm.ProductDescription == testProduct.ProductDescription)
        )
    )
    .ReturnsAsync(testProduct);

Everything else could remain the same.

like image 151
Nkosi Avatar answered Nov 09 '22 23:11

Nkosi