1

I have a method that gets all records from some database table:

public async Task<List<T>> GetAllRecordsAsync<T>(EntitiesNew source) where T : class, IGetAllRecords
{
    if (source != null) 
        return await source.Set<T>().ToListAsync();
    return null;
}

I am trying to write an unit test. My test method is:

 public async Task GetAllRecordsAsyncTest()
    {
        var data = new List<TABLE_NAME>
        {
            new TABLE_NAME {VALID= 1, NAME = "test 1"},
            new TABLE_NAME {VALID= 1, NAME = "test 2"}
        }.AsQueryable();

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

        var mockContext = new Mock<EntitiesNew>();
        mockContext.Setup(x => x.TABLE_NAME).Returns(mockSet.Object);

        var database = new Database();
        var records = await database.GetAllRecordsAsync<TABLE_NAME>(mockContext.Object);
        int numberOfRecords = records.Count;
        Assert.AreEqual(2, numberOfRecords, "Wrong number of records.");
    }

The problem is that I get actual number of records from database. How can I get number of records from mocked object?

noseratio
  • 59,932
  • 34
  • 208
  • 486
Sasha
  • 833
  • 1
  • 20
  • 40

4 Answers4

2

I think rather than mocking the ORM you can implement the Repository pattern to encapsulate data access and then mock each repository. It will be much easier to mock as you only need to mock GetAllRecordsAsync<T> rather than the internals.

You can try doing something like this:

interface IRepository<T> where T : class, IGetAllRecords
{
    Task<List<T>> GetAllRecordsAsync(EntitiesNew source);
}

public class Repository<T> : IRepository<T> where T : class, IGetAllRecords
{
    public async Task<List<T>> GetAllRecordsAsync(EntitiesNew source)
    {
        return await Task.FromResult<List<T>>(null);
    }
}

public class Foo : IGetAllRecords {}

public class FooRepository : Repository<Foo>
{
}

I am not familliar with the mocking framework you are using but potentially you would mock IRepository<Foo> like this:

var mockSet = new Mock<IRepository<Foo>>();
mockSet.Setup(x => x.GetAllRecordsAsync(null)).Returns(Task.FromResult<List<Foo>>(/*desired return value*/));
NeddySpaghetti
  • 13,187
  • 5
  • 32
  • 61
  • Thank you for pointing. It gave me direction, of the possible way to solve it, but it is not exactly what helped me. +1 – Sasha Jun 02 '14 at 07:49
1

My guess is that you have to change mockContext.Setup(x => x.TABLE_NAME) and instead mock the Set<T>() function you are using to query the data.

Joanvo
  • 5,677
  • 2
  • 25
  • 35
  • Do you mean that I need to change mockContext.Setup(x => x.TABLE_NAME).Returns(mockSet.Object); to mockContext.Setup(x => x.Set()).Returns(mockSet.Object);? – Sasha May 30 '14 at 12:00
  • Yes. And of course change the type you return at the mock, for that piece of code I can imagine that mock should return the data object directly. – Joanvo May 30 '14 at 12:10
  • I've got error - Invalid setup on a non-virtual member: x.Set() – Sasha Jun 02 '14 at 06:35
1

According to this answer, I've added interface to my entity class:

public interface IDbContext
{
    DbSet<T> Set<T>() where T: class; 
}
public class EntitiesNew : DbContext, IDbContext
{
    public EntitiesNew()
        : base("name=EntitiesNew")
    {
    }}

Then I've changed my method in repository class:

public async Task<List<T>> GetAllRecordsAsync<T>(IDbContext source) where T : class, IGetAllRecords
{
    if (source != null) 
        return await source.Set<T>().ToListAsync();
    return null;
}

And finally my test method now looks following way:

[TestMethod]
public async Task GetAllRecordsAsyncTest()
{
    var data = new List<TABLE_NAME>
    {
        new TABLE_NAME {VALID= 1, NAME = "test 1"},
        new TABLE_NAME {VALID= 1, NAME = "test 2"}
    }.AsQueryable();

    var mockSet = new Mock<DbSet<TABLE_NAME>>();
    mockSet.As<IQueryable<TABLE_NAME>>().Setup(m => m.Provider).Returns(new TestDbAsyncQueryProvider<TABLE_NAME>(data.Provider));
    mockSet.As<IQueryable<TABLE_NAME>>().Setup(m => m.Expression).Returns(data.Expression);
    mockSet.As<IQueryable<TABLE_NAME>>().Setup(m => m.ElementType).Returns(data.ElementType);
    mockSet.As<IQueryable<TABLE_NAME>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
    mockSet.As<IDbAsyncEnumerable<TABLE_NAME>>().Setup(x=>x.GetAsyncEnumerator()).Returns(new TestDbAsyncEnumerator<TABLE_NAME>(data.GetEnumerator()));
    var mockContext = new Mock<IDbContext>();
    mockContext.Setup(x => x.TABLE_NAME).Returns(mockSet.Object);

    var database = new Database();
    var records = await database.GetAllRecordsAsync<TABLE_NAME>(mockContext.Object);
    int numberOfRecords = records.Count;
    Assert.AreEqual(2, numberOfRecords, "Wrong number of records.");
}
Community
  • 1
  • 1
Sasha
  • 833
  • 1
  • 20
  • 40
1

Another option is to use an in memory database:

var data = RETURN_DATA;
var optionsBuilder = new DbContextOptionsBuilder<DB_NAME>()
  .UseInMemoryDatabase(Guid.NewGuid().ToString());

var context = new DB_NAME(optionsBuilder.Options);
  context.TABLE_NAME.Add(data);
  context.SaveChanges();