Unit testing: How to test generic repository

4

I am trying to test my generic repository which looks like this

public class GenericRepository<T> : IGenericRepository<T> where T : BaseEntity
{
    protected readonly DbContext DbContext;
    public GenericRepository(DbContext dbContext)
    {
        DbContext = dbContext;
    }

    public string Create(T item)
    {
        if (string.IsNullOrEmpty(item.Id))
        {
            item.Id = Guid.NewGuid().ToString("N");
        }
        item.CreatedAt = DateTime.UtcNow;
        DbContext.Entry(item).State = EntityState.Added;
        DbContext.SaveChanges();
        return item.Id;
        /*using (var dbContext = new MyDbContext())
        {
            item.Id = Guid.NewGuid().ToString("N");
            item.CreatedAt = DateTime.UtcNow;
            dbContext.Entry(item).State = EntityState.Added;
            dbContext.SaveChanges();
            return item.Id;
        }*/
    }
    public T GetById(string id)
    {
        return GetFirst(x => x.Id == id);
    }      

    public T GetFirst(Expression<Func<T, bool>> @where, params Expression<Func<T, object>>[] nav)
    {
        return GetFiltered(nav).FirstOrDefault(where);
        /*using (var context = new MyDbContext())
        {
            return GetFiltered(context, nav).FirstOrDefault(where);
        }*/
    }


    private IQueryable<T> GetFiltered(params Expression<Func<T, object>>[] nav)
    {
        IQueryable<T> q = DbContext.Set<T>();
        return nav.Aggregate(q, (current, n) => current.Include(n));
    }

}

Based on the microft's testing fundamental site I tried to write few test cases.

Below is unit test code

[TestClass]
public class GenericRepositoryTest
{
    private Foo _foo;
    private IQueryable<Foo> _fooList;
    private Mock<DbSet<Foo>> _mockSet;  

    [TestInitialize]
    public void Setup()
    {
        _foo = new Foo
        {            
            EmailId = "foo@bar.com",
            FirstName = "foo",
            LastName = "bar",               
            ProfileId = 27,
            IsDeleted = false,
        };  

        _fooList = new List<Foo>
        {
            new Foo{EmailId = "one@bar.com", FirstName = "one", LastName = "bar", ProfileId = 28, IsDeleted = false}, 
            new Foo{EmailId = "two@bar.com", FirstName = "two", LastName = "bar", ProfileId = 29, IsDeleted = false},    
        }.AsQueryable();
        _mockSet = new Mock<DbSet<Foo>>();
        _mockSet.As<IQueryable<Foo>>().Setup(m => m.Provider).Returns(_fooList.Provider);
        _mockSet.As<IQueryable<Foo>>().Setup(m => m.Expression).Returns(_fooList.Expression);
        _mockSet.As<IQueryable<Foo>>().Setup(m => m.ElementType).Returns(_fooList.ElementType);
        _mockSet.As<IQueryable<Foo>>().Setup(m=>m.GetEnumerator()).Returns(_fooList.GetEnumerator());
    }

    [TestMethod]
    public void Create_GivenEntity_ReturnsGuidId()
    {
        //Arrange
        var guidId = Guid.NewGuid().ToString("N");
        var dbContext = new Mock<MyDbContext>().Object;

        IGenericRepository<Foo> genericRepository = new Mock<GenericRepository<Foo>>(dbContext).Object;

        //Act
        _waitingQueue.Id = guidId;
        var actualId = genericRepository.Create(_foo);

        //Assert
        Assert.IsNotNull(actualId);
        Assert.AreEqual(actualId, guidId);

    }

    [TestMethod]
    public void GetById_GivenEntityId_ReturnsEntity()
    {
        //Arrange
        var id = Guid.NewGuid().ToString("N");
        _foo.Id = id;

        var mockContext = new Mock<MyDbContext>();
        mockContext.Setup(c => c.Foo).Returns(_mockSet.Object);
        IGenericRepository<Foo> genericRepository = new Mock<GenericRepository<Foo>>(mockContext.Object).Object;

        //Act
        var fooId = genericRepository.Create(_foo);
        var fooObject = genericRepository.GetById(id);

        //Assert
        fooObject.PropertiesShouldEqual(_foo);
    }
}

Here is DbContext

public class MyDbContext : DbContext
{
    public MyDbContext() : base("fakeConnectionString")
    {
    }

    public virtual DbSet<Foo> WaitingQueues { get; set; }
}

I am new to unit testing and I don't know if the approach I am taking is the right one.

Currently, the first test Create_GivenEntity_ReturnsGuidId passes but the second test GetById_GivenEntityId_ReturnsEntity fails.

The error I get is on GetFirst(Expression<Func<T, bool>> @where, params Expression<Func<T, object>>[] nav) method of GenericRepository

This is because the GetFiltered(params Expression<Func<T, object>>[] nav) when called by GetFirst returns null.

Is it becuase at this point T is unknown for GenericRepository<T>?

Error I get is

System.ArgumentNullException
HResult=0x80004003
Message=Value cannot be null.
Parameter name: source

When I debug I can see that GetById(string id) method has proper id passed into it

Can anyone suggest me what should I do? and what approach should I take?

c#
unit-testing
generics
moq
mstest
asked on Stack Overflow Aug 23, 2018 by Cybercop • edited Aug 23, 2018 by Cybercop

1 Answer

1

You did not setup DbContext.Set(), so, as Mock is on Loose Behavior by default, it should returns null.

The type of the set is not correct.

// should be Mock<DbSet<Foo>>
private Mock<DbSet<WaitingQueue>> _mockSet;
// what it MyDbContext ? should not it be DbContext ? has it is in 
// GenericRepository
var mockContext = new Mock<MyDbContext>();
// what is the point of this line ?
mockContext.Setup(c => c.WaitingQueues).Returns(_mockSet.Object);
// how to setup
mockContext.Setup(c => c.Set<Foo>()).Returns(_mockSet.Object);

nav is always null since you call GetFirst with only the predicate.

public T GetById(string id)
{
     // nav is null
     return GetFirst(x => x.Id == id);
}      

Also, if you want to test the class GenericRepository, do not mock it in your tests, otherwise, what's the point to do unit tests on it ?

What you want to test is the logic behind and test if it can handle all inputs.

For ex, for the method GetById, test when id is null, id is empty, id does not refers to an existing entity and a successful test (entity found).

answered on Stack Overflow Aug 23, 2018 by Zysce • edited Aug 23, 2018 by Zysce

User contributions licensed under CC BY-SA 3.0