notlkk notlkk - 10 days ago 5
C# Question

Unit Test with Moq - Value can not be null

I'm using EF6. The generated code is something like:

public partial class MyDataContext : DbContext
{
public MyDataContext() : base("name=mydata")
{
}

public virtual DbSet<Book> Books { get; set; }
}


Then I have a generic repository like:

public class GenericRepository<TObject> where TObject : class
{
protected readonly MyDataContext Context;

protected GenericRepository(MyDataContext context)
{
Context = context;
}

public virtual DbSet<TObject> GetAll()
{
return Context.Set<TObject>();
}
}


Then I have a service that uses the GenericRepository to return data:

public class MyDataService<TObject> where TObject : class
{
private readonly MyDataContext context;

public MyDataService(MyDataContext ct)
{
context = ct;
}

public ICollection<TObject> GetAll()
{
var r = new GenericRepository<TObject>(context);
return r.GetAll().ToList();
}
}


So I can get all books with something like this:

var ds = new MyDataService<Book>(new MyDataContext());
var data = ds.GetAll();


This is working fine. Next I try to use Moq to unit test the above code with something like:

var books = new List<Book>
{
new Book {Id = 1, Name = "BBB"},
new Book {Id = 2, Name = "ZZZ"},
new Book {Id = 3, Name = "AAA"},
}.AsQueryable();

var mockSet = new Mock<DbSet<Book>>();
mockSet.As<IQueryable<Book>>().Setup(m => m.Provider).Returns(books.Provider);
mockSet.As<IQueryable<Book>>().Setup(m => m.Expression).Returns(books.Expression);
mockSet.As<IQueryable<Book>>().Setup(m => m.ElementType).Returns(books.ElementType);
mockSet.As<IQueryable<Book>>().Setup(m => GetEnumerator()).Returns(books.GetEnumerator());

var mockContext = new Mock<MyDataContext>();
mockContext.Setup(c => c.Books).Returns(mockSet.Object);

var service = new MyDataService<Book>(mockContext.Object);
var data = service.GetAll();


However, I get the
"Value cannot be null.\r\nParameter name: source"
error on the last line. When I step into the code I see Books collection in the context object is empty.

What am I doing wrong?

Answer

That is because test sets up .Setup(c => c.Books) in the data context but in actual code accesses Context.Set<TObject>() in the GetAll() method, so for test it will end up as being null.

try changing to

mockContext.Setup(c => c.Set<Book>()).Returns(mockSet.Object);