Svlet
Svlet

Reputation: 13

Unit testing with Moq and a Generic Repository

I'm creating my first test unit with Moq, but cannot seem to make it work.

I have a Generic repository that injects my ApplicationDbContext. I'm trying to recieve a list of all the foods stored in a database. In my real service I use Simple Injector and everything works fine there.

ApplicationDbContext:

public class ApplicationDbContext : IdentityDbContext<AppUser>
{
    public ApplicationDbContext()
        : base("ApplicationDbContext")
    {
    }
    ...
}

Generic repository:

public class Repository<T> : IRepository<T> where T : class
{
    private ApplicationDbContext _context;
    private readonly IDbSet<T> _entities;

    public Repository(ApplicationDbContext context)
    {
        _context = context;
        _entities = _context.Set<T>();
    }

    .. async methods .. (GetAllAsync)
}

Moq test:

[TestClass]
public class FoodServicesTest
{
    private Mock<IRepository<Food>> _foodRepository;

    [TestInitialize]
    public void Initialize()
    {
        _foodRepository = new Mock<IRepository<Food>>();
    }

    [TestMethod]
    public async Task CanGetAllFoods()
    {
        // Before edit 2
        //IList<Food> foods = await _foodRepository.Object.GetAllAsync();
        //_foodRepository.Setup(m => m.GetAllAsync()).ReturnsAsync(foods);

        _foodRepository.Setup(m => m.GetAllAsync()).ReturnsAsync(List<Food>());
        IList<Food> foods = await _foodRepository.Object.GetAllAsync();

        Assert.IsTrue(foods.Count >= 1);
    }
}

EDIT 2:

After placing the Setup above GetAllAsync() (thanks to Patrick Quirk) and replacing its parameter to 'new List()' the food list doesn't return a null anymore but a count 0 which presumably is better but I expect it to be 2 (like in service).

Upvotes: 1

Views: 3698

Answers (2)

Massimo Franciosa
Massimo Franciosa

Reputation: 554

the return value is an empty list. this is specified by this line of your code

_foodRepository.Setup(m => m.GetAllAsync()).ReturnsAsync(new List<Food>());

the instruction above is actually telling to the mock object to return a new empty list when GetAllAsync is invoked.

You should instead create new Food objects to "simulate" a result from the database, like so:

var foodList = new List<Food>();
foodList.Add(new Food() { ...insert your mocked values here });
foodList.Add(new Food() { ...insert your mocked values here });
_foodRepository.Setup(m => m.GetAllAsync()).ReturnsAsync(foodList);

EDIT

looking better at the code I can only see that you're just using the mock object and see if returns a result. are you sure that is really needed this test? is useful to use mock objects on repositories when there's some business logic involved to be tested. maybe your code was just rewritten for making the question but is worthwhile to point this out.

Upvotes: 1

esiprogrammer
esiprogrammer

Reputation: 1438

You can specify the value to return this way:

var foods=new List<Food>();
//// add two items here
foods.Add(new food(){.. set values });
foods.Add(new food(){.. set values });

_foodRepository.Setup(m => m.GetAllAsync()).ReturnsAsync(foods);
IList<Food> foods = await _foodRepository.Object.GetAllAsync();

Upvotes: 0

Related Questions