How to execute expressions in moq Repository? - c#

I have IGeneric repository having function declaration
T FindBy(Expression<Func<T, bool>> predicate);
and in Generic Repository Class
public T FindBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
return _dbset.FirstOrDefault(predicate);
}
and having the unit Test class,
create a mock repository and initialize the data in to the mock database
[TestClass]
public class ServiceTest
{
private IClientRepository mockClientRepository;
public ServiceTest()
{
IList<ClientData> client = new List<ClientData>
{
new ClientData{ Name= "Mike", Address ="Uk" },
new ClientData{ Name= "Jane", Address ="US" },
};
Mock<IClientRepository> _mockRepository = new Mock<IClientRepository>();
_mockRepository.Setup(m => m.FindBy(It.IsAny<Expression<Func<ClientData, bool>>>())).Returns((string apiClient) =>
{
var data = client.Where(x => x.Hash == apiClient).FirstOrDefault();
return data;
});
this.mockClientRepository = _mockRepository.Object;
}
[TestMethod]
public void IsDataFindByName()
{
ClientData testResult = this.mockClientRepository.FindBy(i => i.Name== "Mike");
Assert.IsNotNull(testResult);
}
i found an exception when i run the test
Additional information: Object of type 'System.Linq.Expressions.Expression`1[System.Func`2[Adminportal.Entities.ClientData ,System.Boolean]]' cannot be converted to type 'System.String'.
I dont know how to pass it,

The parameterful Returns method expect its parameter to be of same type as mocked method's parameter. You use .Returns((string apiClient) when Expression<Func<ClientData, bool>> is expected. Simply change it to:
.Returns((Expression<Func<ClientData, bool>> expression) =>
{
var data = client.Where(expression.Compile()).FirstOrDefault();
return data;
});

Related

How to mock Nhibernate .ToListAsync() in Unit-test with moq?

I'm trying create unit-tests in ASP.NET Core MVC application with moq. Unfortunately, Nhibernate.ToListAsync() is not supported Linq IQueryable dataset and throw System.NotSupportedException: 'Source Provider must be a INhQueryProvider'.
In this code I mock INhQueryProvider, but it's not enough:
var entities = new List<RequestRole>
{
new RequestRole()
{
Id = 0,
RequestOperator = new RequestOperator() { Id = 1 }
},
new RequestRole()
{
Id = 1,
RequestOperator = new RequestOperator() { Id = 2 }
}
}
.AsQueryable();
// for ToListAsync Mock INhQueryProvider and set it into IQueryable
var queryableProviderMock = new Mock<INhQueryProvider>();
queryableProviderMock.Setup(x => x.ExecuteAsync<IEnumerable<RequestRole>>(It.IsAny<Expression>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(entities);
var queryableMock = new Mock<IQueryable<RequestRole>>();
queryableMock.Setup(x => x.Provider).Returns(queryableProviderMock.Object);
queryableMock.Setup(x => x.Expression).Returns(entities.Expression);
queryableMock.Setup(x => x.GetEnumerator()).Returns(entities.GetEnumerator());
queryableMock.Setup(x => x.ElementType).Returns(entities.ElementType);
// mock CreateQuery, without this Linq.Where throwing "System.NotSupportedException: 'Source Provider must be a INhQueryProvider'"
queryableProviderMock.As<INhQueryProvider>()
.Setup(x => x.CreateQuery<RequestRole>(It.IsAny<Expression>()))
.Returns(queryableMock.Object);
var session = new Mock<ISession>();
session.Setup(s => s.Query<RequestRole>()).Returns(queryableMock.Object);
var returns = session.Object.Query<RequestRole>();
// check work
var tolistasync = await returns
.Where(x => x.Id != 0)
.ToListAsync();
In this case Linq.Where conditions not working, because I set same object instead of filtered.
Seems like I should correctly mock INhQueryProvider.CreateQuery, but how?
You'll need to instruct CreateQuery to use the expression. Just returning the mocked queryable isn't going to do anything as you've seen. Additionally CreateQuery is going to need to return an IQueryable with a provider that implements INhQueryProvider. The problem with that is the Provider property doesn't have a setter so you can't set it on an existing queryable.
The way I've solved a similar problem is to create my own sequence where I can set the provider.
Start with creating classes that implement IQueryable<T> and INhQueryProvider; for brevity I'm only implementing what is required to pass the OP use case. Note that CreateQuery<T> returns a queryable with a provider that implements INhQueryProvider:
public class TestingQueryable<T> : IQueryable<T>
{
private readonly IQueryable<T> _queryable;
public TestingQueryable(IQueryable<T> queryable)
{
_queryable = queryable;
Provider = new TestingQueryProvider<T>(_queryable);
}
public Type ElementType => _queryable.ElementType;
public Expression Expression => _queryable.Expression;
public IQueryProvider Provider { get; }
public IEnumerator<T> GetEnumerator()
{
return _queryable.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _queryable.GetEnumerator();
}
}
public class TestingQueryProvider<T> : INhQueryProvider
{
public TestingQueryProvider(IQueryable<T> source)
{
Source = source;
}
public IQueryable<T> Source { get; set; }
public IQueryable CreateQuery(Expression expression)
{
throw new NotImplementedException();
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new TestingQueryable<TElement>(Source.Provider.CreateQuery<TElement>(expression));
}
public object Execute(Expression expression)
{
throw new NotImplementedException();
}
public TResult Execute<TResult>(Expression expression)
{
return Source.Provider.Execute<TResult>(expression);
}
public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
{
return Task.FromResult(Execute<TResult>(expression));
}
public int ExecuteDml<T1>(QueryMode queryMode, Expression expression)
{
throw new NotImplementedException();
}
public Task<int> ExecuteDmlAsync<T1>(QueryMode queryMode, Expression expression, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public IFutureEnumerable<TResult> ExecuteFuture<TResult>(Expression expression)
{
throw new NotImplementedException();
}
public IFutureValue<TResult> ExecuteFutureValue<TResult>(Expression expression)
{
throw new NotImplementedException();
}
public void SetResultTransformerAndAdditionalCriteria(IQuery query, NhLinqExpression nhExpression, IDictionary<string, Tuple<object, IType>> parameters)
{
throw new NotImplementedException();
}
}
Update your query provider setup to use your IQueryable implementation:
queryProviderMock
.Setup(x => x.CreateQuery<RequestRole>(It.IsAny<Expression>()))
.Returns((Expression providedExpression) =>
{
return new TestingQueryable<RequestRole>(queryable.Provider.CreateQuery<RequestRole>(providedExpression));
});
Run .Where(x => x.Id != 0).ToListAsync() and get the expected result:
Working example
You could take it further and just set up the ISession mock to use your IQueryable implementation, do away with mocking the query provider if you don't need to specifically mock it. I don't normally mock what a mock returns if you know what I mean so this would meet my peer review standards.
[Test]
public async Task Test2()
{
var requestRoles = new List<RequestRole>();
requestRoles.Add(new RequestRole { Id = 0, RequestOperator = new RequestOperator { Id = 1 } });
requestRoles.Add(new RequestRole { Id = 1, RequestOperator = new RequestOperator { Id = 2 } });
var sessionMock = new Mock<ISession>();
sessionMock.Setup(s => s.Query<RequestRole>()).Returns(new TestingQueryable<RequestRole>(requestRoles.AsQueryable()));
var query = sessionMock.Object.Query<RequestRole>();
var result = await query.Where(x => x.Id != 0).ToListAsync();
Assert.Multiple(() =>
{
Assert.That(result.Count, Is.EqualTo(1));
Assert.That(result.Single(), Is.EqualTo(requestRoles.Last()));
});
}

Verify Expression<Func<T, bool>> argument in a unit test with NSubstitute

I'm working on a unit test and I'd like to verify that a mock object received the proper predicate argument. However, I fail to make it work.
Here's a skeleton of the code:
public interface IRepository<T>
{
Task<T> SingleOrDefaultAsync(Expression<Func<T, bool>> predicate);
}
public class MyClass
{
private readonly IRepository<Foo> _repository
public MyClass(IRepository<Foo> repository)
{
_repository = repository;
}
public Task<bool> MyMethod(int id)
{
var foo = _repository.SingleOrDefaultAsync(x => x.Id == id);
return foo != null;
}
}
and in my test class I have the following method
public async Task MyTestMethod()
{
var repository = Substitute.For<IRepository<Foo>>();
repository.SingleOrDefaultAsync(x => x.Id == 123).Returns(Task.FromResult(new Foo()));
var myClass = new MyClass(repository);
var result = await myClass.MyMethod(123);
result.Should().BeTrue();
}
But as mentioned above, this test fails. I could make it pass by using Arg.Any<Expression<Func<Foo, bool>>, but it doesn't feel right.
Anyone has a suggestion what I'm doing wrong?
Capture the expression passed to the mock and use it in the Returns to verify the expected behavior.
For example
public async Task MyTestMethod() {
//Arrange
var id = 123;
var model = new Foo() {
Id = id;
}
var repository = Substitute.For<IRepository<Foo>>();
repository.SingleOrDefaultAsync(Arg.Any<Expression<Func<Foo, bool>>())
.Returns(args => {
var expression = args.Arg<Expression<Func<Foo, bool>>(); //capture expression
Foo result = expression.Compile()(model) ? model : null; //use to verify behavior
Task.FromResult(result);
});
var myClass = new MyClass(repository);
//Act
var actual = await myClass.MyMethod(id);
//Assert
actual.Should().BeTrue();
}

Unit Test Mock a class inheriting multiple interfaces and a class

First the code,
Generic Interface:
public interface IEntityService<TEntity> where TEntity : class
{
IQueryable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "");
Task<TEntity> GetByIDAsync(object id);
Task<TEntity> GetFirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate);
}
Generic Class with interface implementation:
public class EntityService<TEntity> : IEntityService<TEntity> where TEntity : class
{
protected IContext IContext;
protected DbSet<TEntity> IDbSet;
public EntityService(IContext context)
{
IContext = context;
IDbSet = IContext.Set<TEntity>();
}
public virtual IQueryable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = IDbSet;
if (filter != null)
{
query = query.Where(filter);
}
query = includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Aggregate(query, (current, includeProperty) => current.Include(includeProperty));
if (orderBy != null)
{
return orderBy(query);
}
return query;
}
public virtual async Task<TEntity> GetByIDAsync(object id)
{
return await IDbSet.FindAsync(id);
}
public virtual async Task<TEntity> GetFirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate)
{
return await IDbSet.FirstOrDefaultAsync(predicate);
}
}
Specific interface:
public interface ILoginService
{
Task<UserProfileViewModel> GetLoginDetailAsync(string userName);
}
Specific class: Implementing generic class and specific interface
public class LoginService : EntityService<UserAccount>, ILoginService
{
private readonly IContext _iContext;
public LoginService(IContext context): base(context)
{
_iContext = context;
}
async Task<UserProfileViewModel> ILoginService.GetLoginDetailAsync(string userName)
{
var userAcount = await GetFirstOrDefaultAsync(c => c.Username.ToLower() == userName.Trim().ToLower() && c.Active == true);
if (userAcount != null)
{
return Mapper.Map<UserAccount, UserProfileViewModel>(userAcount);
}
return null;
}
}
Now, I am supposed to test LoginService the one and only method it has
Here's the test code
[Test]
public async Task GetLoginDetailAsync_InvalidUsername_ReturnsNull()
{
var userName = "should not exist!";
var userAccount = new List<UserAccount>()
{
new UserAccount
{
ID = 1,
Name = "Test User"
}
}.AsQueryable();
var mockSet = new Mock<DbSet<UserAccount>>();
var userProfileViewModel = new UserProfileViewModel
{
ID = 1,
Name = Guid.NewGuid().ToString().Substring(0, 8)
};
_context.Setup(c => c.Set<UserAccount>()).Returns(mockSet.Object);
loginService = new LoginService(_context.Object);
mockSet.As<IDbAsyncEnumerable<UserAccount>>().
Setup(m => m.GetAsyncEnumerator()).
Returns(new TestDbAsyncEnumerator<UserAccount>(userAccount.GetEnumerator()));
mockSet.As<IQueryable<UserAccount>>()
.Setup(m => m.Provider)
.Returns(new TestDbAsyncQueryProvider<UserAccount>(userAccount.Provider));
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Expression).Returns(userAccount.Expression);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.ElementType).Returns(userAccount.ElementType);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.GetEnumerator()).Returns(userAccount.GetEnumerator());
var result = await ((ILoginService)loginService).GetLoginDetailAsync(userName);
Assert.IsNull(result);
}
Now, these TestDbAsyncEnumerator and TestDbAsyncQueryProvider are taken from msdn to test Async queries in EF.
The problem
The test throws an exception, that Message: System.NotImplementedException : The member 'IQueryable.Provider' has not been implemented on type 'DbSet1Proxy' which inherits from 'DbSet1'. Test doubles for 'DbSet1' must provide implementations of methods and properties that are used. Basically, I have not setup the FirstOrDefaultAsync for mockSet that is getting called in GetLoginDetailAsync (it calls to EntityService, that ends up calling the FirstOrDefaultAsync of IDbSet).
I don't know how can I mock that, because the LoginService doesn't directly inherits it. It inherit's the EntityService which in turn has that generic method FirstOrDefaultAsync. I am stuck at how to set up that.
One another thing that I thought was try this
var loginMock = new Mock<LoginService>(_context.Object);
loginMock.As<ILoginService>().Setup(c => c.GetLoginDetailAsync(It.IsAny<string>())).Returns(Task.FromResult<UserProfileViewModel>(null));
loginMock.As<IEntityService<UserAccount>>().Setup(c => c.GetFirstOrDefaultAsync(It.IsAny<Expression<Func<UserAccount, bool>>>())).Returns(Task.FromResult(userAccount.First()));
But I don't think this is the correct way to go, as I would only be testing the mock object. Can anyone suggest me how do I get to setup and test/mock this GetFirstOrDefaultAsync, or am I totally going in a wrong direction?
UPDATE AFTER ANSWER:
After the answer from #ODawgG, I am updating this. The test worked fine as specified in answer, but now the other test is failing. I wanted to test, if a particular user exits in the system.
Here's the test code:
[Test]
public async Task Test3()
{
var userAccount = new List<UserAccount>()
{
new UserAccount
{
ID = 1,
Username = "User"
}
}.AsQueryable();
var mockSet = new Mock<DbSet<UserAccount>>();
mockSet.As<IDbAsyncEnumerable<UserAccount>>().
Setup(m => m.GetAsyncEnumerator()).
Returns(new TestDbAsyncEnumerator<UserAccount>(userAccount.GetEnumerator()));
mockSet.As<IQueryable<UserAccount>>()
.Setup(m => m.Provider)
.Returns(new TestDbAsyncQueryProvider<UserAccount>(userAccount.Provider));
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Expression).Returns(userAccount.Expression);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.ElementType).Returns(userAccount.ElementType);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.GetEnumerator()).Returns(userAccount.GetEnumerator());
AutoMapConfiguration.Configure();
var entityService = new Mock<IEntityService<UserAccount>>();
entityService
.Setup(service => service.GetFirstOrDefaultAsync(It.IsAny<Expression<Func<UserAccount, bool>>>()))
.ReturnsAsync(
(Expression<Func<UserAccount, bool>> predicate) => userAccount.FirstOrDefault(predicate)
);
var loginService = new LoginService(entityService.Object);
// Act
var result = await ((ILoginService)loginService).GetLoginDetailAsync("User");
// Assert
Assert.IsNotNull(result);
}
This test should pass, as it should query on the userAccount but it fails, when I was debugging, and it went inside the LoginService, and I checked _entityService.Get().ToList() it says 0 count, while it should really say count 1, the userAccount that I have setup.
Afaik, the IDbSet is still not setup, and that's why the count is 0, and it's not returning true. How do I setup that? If it is correct, then why is this test failing? Also, I know that moq isn't really good for testing expression, but I got this predicate part of code from here.
I agree with #Fabio. There no need to inherit from EntityService<T> but rather inject into your LogService class.
Refactored your class would look like the following:
public class LoginService : ILoginService
{
private readonly IEntityService<UserAccount> _entityService;
public LoginService(IEntityService<UserAccount> entityService)
{
_entityService = entityService;
}
async Task<UserProfileViewModel> ILoginService.GetLoginDetailAsync(string userName)
{
var userAcount = await _entityService.GetFirstOrDefaultAsync(c => c.Username.ToLower() == userName.Trim().ToLower() && c.Active);
if (userAcount != null)
{
return Mapper.Map<UserAccount, UserProfileViewModel>(userAcount);
}
return null;
}
}
And your test would look like this:
[Test]
public async Task GetLoginDetailAsync_InvalidUsername_ReturnsNull()
{
// Arrange
MapperInitialize.Configure();
var entityService = new Mock<IEntityService<UserAccount>>();
entityService
.Setup(service => service.GetFirstOrDefaultAsync(It.IsAny<Expression<Func<UserAccount, bool>>>()))
.ReturnsAsync(new UserAccount
{
ID = 1,
Name = "Test User"
});
var loginService = new LoginService(entityService.Object);
// Act
var result = await ((ILoginService)loginService).GetLoginDetailAsync(It.IsAny<string>());
// Assert
Assert.IsNotNull(result);
}
Here's the updated test to include testing the expression:
[Test]
public async Task GetLoginDetailAsync_InvalidUsername_ReturnsNull()
{
// Arrange
MapperInitialize.Configure();
var entityService = new Mock<IEntityService<UserAccount>>();
var userAccount = new UserAccount
{
ID = 1,
Username = "Test User",
Active = true
};
var expressionResult = false;
entityService
.Setup(service => service.GetFirstOrDefaultAsync(It.IsAny<Expression<Func<UserAccount, bool>>>()))
.Callback<Expression<Func<UserAccount, bool>>>(expression =>
{
expressionResult = expression.Compile().Invoke(userAccount);
})
.ReturnsAsync(userAccount);
var loginService = new LoginService(entityService.Object);
// Act
var result = await ((ILoginService)loginService).GetLoginDetailAsync("Test User");
// Assert
Assert.IsTrue(expressionResult);
Assert.IsNotNull(result);
}

How to mock an async repository with Entity Framework Core

I'm trying to create a unit test for a class that calls into an async repository. I'm using ASP.NET Core and Entity Framework Core. My generic repository looks like this.
public class EntityRepository<TEntity> : IEntityRepository<TEntity> where TEntity : class
{
private readonly SaasDispatcherDbContext _dbContext;
private readonly DbSet<TEntity> _dbSet;
public EntityRepository(SaasDispatcherDbContext dbContext)
{
_dbContext = dbContext;
_dbSet = dbContext.Set<TEntity>();
}
public virtual IQueryable<TEntity> GetAll()
{
return _dbSet;
}
public virtual async Task<TEntity> FindByIdAsync(int id)
{
return await _dbSet.FindAsync(id);
}
public virtual IQueryable<TEntity> FindBy(Expression<Func<TEntity, bool>> predicate)
{
return _dbSet.Where(predicate);
}
public virtual void Add(TEntity entity)
{
_dbSet.Add(entity);
}
public virtual void Delete(TEntity entity)
{
_dbSet.Remove(entity);
}
public virtual void Update(TEntity entity)
{
_dbContext.Entry(entity).State = EntityState.Modified;
}
public virtual async Task SaveChangesAsync()
{
await _dbContext.SaveChangesAsync();
}
}
Then I have a service class that calls FindBy and FirstOrDefaultAsync on an instance of the repository:
public async Task<Uri> GetCompanyProductURLAsync(Guid externalCompanyID, string productCode, Guid loginToken)
{
CompanyProductUrl companyProductUrl = await _Repository.FindBy(u => u.Company.ExternalCompanyID == externalCompanyID && u.Product.Code == productCode.Trim()).FirstOrDefaultAsync();
if (companyProductUrl == null)
{
return null;
}
var builder = new UriBuilder(companyProductUrl.Url);
builder.Query = $"-s{loginToken.ToString()}";
return builder.Uri;
}
I'm trying to mock the repository call in my test below:
[Fact]
public async Task GetCompanyProductURLAsync_ReturnsNullForInvalidCompanyProduct()
{
var companyProducts = Enumerable.Empty<CompanyProductUrl>().AsQueryable();
var mockRepository = new Mock<IEntityRepository<CompanyProductUrl>>();
mockRepository.Setup(r => r.FindBy(It.IsAny<Expression<Func<CompanyProductUrl, bool>>>())).Returns(companyProducts);
var service = new CompanyProductService(mockRepository.Object);
var result = await service.GetCompanyProductURLAsync(Guid.NewGuid(), "wot", Guid.NewGuid());
Assert.Null(result);
}
However, when the test executes the call to the repository, I get the following error:
The provider for the source IQueryable doesn't implement IAsyncQueryProvider. Only providers that implement IEntityQueryProvider can be used for Entity Framework asynchronous operations.
How can I properly mock the repository to get this to work?
Thanks to #Nkosi for pointing me to a link with an example of doing the same thing in EF 6: https://msdn.microsoft.com/en-us/library/dn314429.aspx. This didn't work exactly as-is with EF Core, but I was able to start with it and make modifications to get it working. Below are the test classes that I created to "mock" IAsyncQueryProvider:
internal class TestAsyncQueryProvider<TEntity> : IAsyncQueryProvider
{
private readonly IQueryProvider _inner;
internal TestAsyncQueryProvider(IQueryProvider inner)
{
_inner = inner;
}
public IQueryable CreateQuery(Expression expression)
{
return new TestAsyncEnumerable<TEntity>(expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new TestAsyncEnumerable<TElement>(expression);
}
public object Execute(Expression expression)
{
return _inner.Execute(expression);
}
public TResult Execute<TResult>(Expression expression)
{
return _inner.Execute<TResult>(expression);
}
public IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression)
{
return new TestAsyncEnumerable<TResult>(expression);
}
public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
{
return Task.FromResult(Execute<TResult>(expression));
}
}
internal class TestAsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>, IQueryable<T>
{
public TestAsyncEnumerable(IEnumerable<T> enumerable)
: base(enumerable)
{ }
public TestAsyncEnumerable(Expression expression)
: base(expression)
{ }
public IAsyncEnumerator<T> GetEnumerator()
{
return new TestAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}
IQueryProvider IQueryable.Provider
{
get { return new TestAsyncQueryProvider<T>(this); }
}
}
internal class TestAsyncEnumerator<T> : IAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public TestAsyncEnumerator(IEnumerator<T> inner)
{
_inner = inner;
}
public void Dispose()
{
_inner.Dispose();
}
public T Current
{
get
{
return _inner.Current;
}
}
public Task<bool> MoveNext(CancellationToken cancellationToken)
{
return Task.FromResult(_inner.MoveNext());
}
}
And here is my updated test case that uses these classes:
[Fact]
public async Task GetCompanyProductURLAsync_ReturnsNullForInvalidCompanyProduct()
{
var companyProducts = Enumerable.Empty<CompanyProductUrl>().AsQueryable();
var mockSet = new Mock<DbSet<CompanyProductUrl>>();
mockSet.As<IAsyncEnumerable<CompanyProductUrl>>()
.Setup(m => m.GetEnumerator())
.Returns(new TestAsyncEnumerator<CompanyProductUrl>(companyProducts.GetEnumerator()));
mockSet.As<IQueryable<CompanyProductUrl>>()
.Setup(m => m.Provider)
.Returns(new TestAsyncQueryProvider<CompanyProductUrl>(companyProducts.Provider));
mockSet.As<IQueryable<CompanyProductUrl>>().Setup(m => m.Expression).Returns(companyProducts.Expression);
mockSet.As<IQueryable<CompanyProductUrl>>().Setup(m => m.ElementType).Returns(companyProducts.ElementType);
mockSet.As<IQueryable<CompanyProductUrl>>().Setup(m => m.GetEnumerator()).Returns(() => companyProducts.GetEnumerator());
var contextOptions = new DbContextOptions<SaasDispatcherDbContext>();
var mockContext = new Mock<SaasDispatcherDbContext>(contextOptions);
mockContext.Setup(c => c.Set<CompanyProductUrl>()).Returns(mockSet.Object);
var entityRepository = new EntityRepository<CompanyProductUrl>(mockContext.Object);
var service = new CompanyProductService(entityRepository);
var result = await service.GetCompanyProductURLAsync(Guid.NewGuid(), "wot", Guid.NewGuid());
Assert.Null(result);
}
Try to use my Moq/NSubstitute/FakeItEasy extension MockQueryable:
supported all Sync/Async operations (see more examples here)
//1 - create a List<T> with test items
var users = new List<UserEntity>()
{
new UserEntity,
...
};
//2 - build mock by extension
var mock = users.AsQueryable().BuildMock();
//3 - setup the mock as Queryable for Moq
_userRepository.Setup(x => x.GetQueryable()).Returns(mock.Object);
//3 - setup the mock as Queryable for NSubstitute
_userRepository.GetQueryable().Returns(mock);
DbSet also supported
//2 - build mock by extension
var mock = users.AsQueryable().BuildMockDbSet();
//3 - setup DbSet for Moq
var userRepository = new TestDbSetRepository(mock.Object);
//3 - setup DbSet for NSubstitute
var userRepository = new TestDbSetRepository(mock);
Notes:
AutoMapper is also supported from 1.0.4 ver
DbQuery supported from 1.1.0 ver
EF Core 3.0 supported from 3.0.0 ver
.Net 5 supported from 5.0.0 ver
Much less code solution. Use the in-memory db context which should take care of bootstrapping all the sets for you. You no longer need to mock out the DbSet on your context but if you want to return data from a service for example, you can simply return the actual set data of the in-memory context.
DbContextOptions< SaasDispatcherDbContext > options = new DbContextOptionsBuilder< SaasDispatcherDbContext >()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
_db = new SaasDispatcherDbContext(optionsBuilder: options);
I'm maintaining two open-source projects that do the heavy lifting of setting up the mocks and actually emulates SaveChanges(Async).
For EF Core: https://github.com/huysentruitw/entity-framework-core-mock
For EF6: https://github.com/huysentruitw/entity-framework-mock
Both projects have Nuget packages with integration for Moq or NSubstitute.
Here is a port of the accepted answer to F#, I just did it for myself and thought it may save someone the time. I have also updated the example to match the updated C#8 IAsyncEnumarable API and tweaked the Mock setup to be generic.
type TestAsyncEnumerator<'T> (inner : IEnumerator<'T> ) =
let inner : IEnumerator<'T> = inner
interface IAsyncEnumerator<'T> with
member this.Current with get() = inner.Current
member this.MoveNextAsync () = ValueTask<bool>(Task.FromResult(inner.MoveNext()))
member this.DisposeAsync () = ValueTask(Task.FromResult(inner.Dispose))
type TestAsyncEnumerable<'T> =
inherit EnumerableQuery<'T>
new (enumerable : IEnumerable<'T>) =
{ inherit EnumerableQuery<'T> (enumerable) }
new (expression : Expression) =
{ inherit EnumerableQuery<'T> (expression) }
interface IAsyncEnumerable<'T> with
member this.GetAsyncEnumerator cancellationToken : IAsyncEnumerator<'T> =
new TestAsyncEnumerator<'T>(this.AsEnumerable().GetEnumerator())
:> IAsyncEnumerator<'T>
interface IQueryable<'T> with
member this.Provider with get() = new TestAsyncQueryProvider<'T>(this) :> IQueryProvider
and
TestAsyncQueryProvider<'TEntity>
(inner : IQueryProvider) =
let inner : IQueryProvider = inner
interface IAsyncQueryProvider with
member this.Execute (expression : Expression) =
inner.Execute expression
member this.Execute<'TResult> (expression : Expression) =
inner.Execute<'TResult> expression
member this.ExecuteAsync<'TResult> ((expression : Expression), cancellationToken) =
inner.Execute<'TResult> expression
member this.CreateQuery (expression : Expression) =
new TestAsyncEnumerable<'TEntity>(expression) :> IQueryable
member this.CreateQuery<'TElement> (expression : Expression) =
new TestAsyncEnumerable<'TElement>(expression) :> IQueryable<'TElement>
let getQueryableMockDbSet<'T when 'T : not struct>
(sourceList : 'T seq) : Mock<DbSet<'T>> =
let queryable = sourceList.AsQueryable();
let dbSet = new Mock<DbSet<'T>>()
dbSet.As<IAsyncEnumerable<'T>>()
.Setup(fun m -> m.GetAsyncEnumerator())
.Returns(TestAsyncEnumerator<'T>(queryable.GetEnumerator())) |> ignore
dbSet.As<IQueryable<'T>>()
.SetupGet(fun m -> m.Provider)
.Returns(TestAsyncQueryProvider<'T>(queryable.Provider)) |> ignore
dbSet.As<IQueryable<'T>>().Setup(fun m -> m.Expression).Returns(queryable.Expression) |> ignore
dbSet.As<IQueryable<'T>>().Setup(fun m -> m.ElementType).Returns(queryable.ElementType) |> ignore
dbSet.As<IQueryable<'T>>().Setup(fun m -> m.GetEnumerator ()).Returns(queryable.GetEnumerator ()) |> ignore
dbSet
A way simpler approach is to write your own ToListAsync in one of the core layers. You dont need any concrete class implementation. Something like:
public static async Task<List<T>> ToListAsync<T>(this IQueryable<T> queryable)
{
if (queryable is EnumerableQuery)
{
return queryable.ToList();
}
return await QueryableExtensions.ToListAsync(queryable);
}
This also has the added benefit that you could use ToListAsync from anywhere in your app without needing to drag EF references all along.
I know this question is old, but I found a nuget package to do this.
MockQueryable
and
MockQueryable.Moq
This does all of the work for you.
[TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")]
[TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")]
[TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")]
public void CreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError)
{
//arrange
var userRepository = new Mock<IUserRepository>();
var service = new MyService(userRepository.Object);
var users = new List<UserEntity>
{
new UserEntity {LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)},
new UserEntity {FirstName = "ExistFirstName"},
new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)},
new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)},
new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}
};
//expect
var mock = users.BuildMock();
userRepository.Setup(x => x.GetQueryable()).Returns(mock);
//act
var ex = Assert.ThrowsAsync<ApplicationException>(() =>
service.CreateUserIfNotExist(firstName, lastName, dateOfBirth));
//assert
Assert.AreEqual(expectedError, ex.Message);
}
Leveraging #Jed Veatch's accepted answer, as well as the comments provided by #Mandelbrotter, the following solution works for .NET Core 3.1 and .NET 5. This will resolve the "Argument expression is not valid" exception that arises from working with the above code in later .NET versions.
TL;DR - Complete EnumerableExtensions.cs code is here.
Usage:
public static DbSet<T> GetQueryableAsyncMockDbSet<T>(List<T> sourceList) where T : class
{
var mockAsyncDbSet = sourceList.ToAsyncDbSetMock<T>();
var queryable = sourceList.AsQueryable();
mockAsyncDbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());
mockAsyncDbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>((s) => sourceList.Add(s));
return mockAsyncDbSet.Object;
}
Then, using Moq and Autofixture, you can do:
var myMockData = Fixture.CreateMany<MyMockEntity>();
MyDatabaseContext.SetupGet(x => x.MyDBSet).Returns(GetQueryableAsyncMockDbSet(myMockData));
For everyone who stuck at mocking DbContext with async queries, IAsyncQueryProvider and other things. Heres example usage of copy-paste types for netcore3.1 and higher. Based on generic DbContextCreation and generic DbSet seed.
public class MyDbContext : DbContext
{
public DbSet<MyEntity> MyEntities { get; set; }
}
public class MyEntity
{
public Guid Id { get; set; }
}
internal class MockDbContextAsynced<TDbContext>
{
private readonly TDbContext _mock;
public TDbContext Object => _mock;
public MockDbContextAsynced()
{
_mock = Activator.CreateInstance<TDbContext>();
}
// suppressed. see full code in source below
}
[Fact]
public void Test()
{
var testData = new List<MyEntity>
{
new MyEntity() { Id = Guid.NewGuid() },
new MyEntity() { Id = Guid.NewGuid() },
new MyEntity() { Id = Guid.NewGuid() },
};
var mockDbContext = new MockDbContextAsynced<MyDbContext>();
mockDbContext.AddDbSetData<MyEntity>(testData.AsQueryable());
mockDbContext.MyEntities.ToArrayAsync();
// or
mockDbContext.MyEntities.SingleAsync();
// or etc.
// To inject MyDbContext as type parameter with mocked data
var mockService = new SomeService(mockDbContext.Object);
}
For full implemented types see this source: https://gist.github.com/Zefirrat/a04658c827ba3ebffe03fda48d53ea11

LINQ to Entities - Generate where predicate dynamically

I have this:
public void AssertReadWorks<T>(
IRepository<T> repository,
T entity,
Expression<Func<T, T, bool>> keyComparer) where T : class
{
entity = repository.GetAll().Single(x => x.Id == entity.Id);
}
[TestMethod]
public void ReadTest_DataFieldGroup()
{
AssertReadWorks(
_unitOfWork.DataFieldSetRepository,
new DataFieldSet { Label = "test", Title = "test" },
(a, b) => a.Id == b.Id);
}
This does not compile since it is not known that T has an Id property. Note that the keyComparer parameter is not used at the moment. I want to use the keyComparer parameter (or another appropriate parameter) to dynamically generate the predicate for Single():
Expression<Func<T, bool>> keyComparingPredicate =
x => a predicate that compares the key of x with the key of `entity`;
entity = repository.GetAll().Single(keyComparingPredicate);
The point is that not all Ts will have Id properties, some will have different names, some will have composite keys. The original AssertReadWorks() works fine if it is not generic. The problem is just building the predicate dynamically in the generic case. If it can be done with something different from the keyComparer paramter, fine with me.
Any ideas? :)
Check, if this fits for you
public T AssertReadWorks<T>(
IRepository<T> repository,
Func<T, bool> keyComparer)
{
return repository.GetAll().Single(keyComparer);
}
Using
[TestMethod]
public void TestInt()
{
var repository = new Repository<int>( new[] {1, 2, 3} );
var intEntity = 3;
AssertReadWorks(repository, e => e == intEntity);
}
[TestMethod]
public void TestString()
{
var repository = new Repository<string>(new[] { "a", "b", "c" });
var stringEntity = "A";
AssertReadWorks(repository, e => string.Equals(e, stringEntity, StringComparison.OrdinalIgnoreCase));
}
[TestMethod]
public void TestThread()
{
var threadEntity = new Thread(() => { });
var repository = new Repository<Thread>(new[] { threadEntity, new Thread(() => { }), new Thread(() => { }) });
AssertReadWorks(repository, e => e.ManagedThreadId == threadEntity.ManagedThreadId);
}
EDIT:
Response for comment:
public void AssertReadWorks<T>(
IRepository<T> repository,
ref T entity,
Func<T, T, bool> keyComparer)
{
var localEntity = entity;
entity = repository.GetAll().Single(e => keyComparer(e, localEntity));
}
Correct me if I'm wrong but is the whole point of this function to check equality? To do this in a generic sense you can use IEquatable Interface. This way your objects knows how to compare themselves to the same object. This should cut down your code reuse and help avoid creating the same expression in multiple places.
So your class would look like this:
public class DataFieldSet : IEquatable<DataFieldSet>
{
public int Id { get; set; }
public bool Equals(DataFieldSet other)
{
return other != null && this.Id == other.Id;
}
}
And your Assert function
public void AssertReadWorks<T>(
IRepository<T> repository,
T entity) where T : IEquatable<T>
{
entity = repository.GetAll().Single(x => entity.Equals(x);
}

Categories

Resources