How do I append a Property into an MOQ Object at Runtime - c#

I am hoping to create a property dynamically at run-time so the Setup can use THAT PROPERTY for its data and/or database value(s):
QUESTION:
How can I append a property to the MOCK INSTANCE dynamically?
EXAMPLE:
public Mock<IRepository<tClaims>> MockClaimsRepository()
{
var repository = new Mock<IRepository<tClaims>>();
// HOW DO I DO THIS?
repository.SetupProperty<Claim>(//* How do I append a dynamic property here *//)
repository.SetupProperty<List<Claims>>(//* How do I append a dynamic property here *//)
repository.Setup(x => x.GetActive()).Returns(repository.Claims.AsQueryable());
repository.Setup(x => x.GetAll()).Returns(repository.Claims.AsQueryable());
repository.Setup(x => x.GetById(repository.Claim.Claim_ID)).Returns(Claim);
repository.Setup(x => x.Find(new object[] { It.IsAny<object>() })).Returns(repository.Claim);
repository.Setup(x => x.Add(repository.Claim)).Verifiable();
repository.Setup(x => x.AddRange(repository.Claims)).Verifiable();
repository.Setup(x => x.Update(repository.Claim)).Verifiable();
repository.Setup(x => x.Delete(repository.Claim)).Verifiable();
repository.Setup(x => x.Delete(It.IsAny<object>())).Verifiable();
return repository;
}

You can't directly add new properties to the mocked object, what you can do is add an implementation of another interface using As<> method with the properties you want.
But if your goal is use this properties to give logic and state to the mock, then you can use variables for that, something like this:
public Mock<IRepository<Claims>> MockClaimsRepository()
{
var repository = new Mock<IRepository<Claims>>();
var claims = new List<Claims>(); // Add variables to be used in the setups
repository.Setup(x => x.GetAll()).Returns(claims.AsQueryable());
repository.Setup(x => x.GetById(It.IsAny<int>())).Returns<int>(id => claims.Find(c => c.Id == id));
repository.Setup(x => x.Add(It.IsAny<Claims>())).Callback<Claims>(c => claims.Add(c));
repository.Setup(x => x.Delete(It.IsAny<Claims>())).Callback<Claims>(c => claims.Remove(c));
...
return repository;
}
These variables will not be disposed when yo return from MockClaimsRepository since you are referencing it in the setups.

You can use SetupAllProperties() ?
Specifies that the all properties on the mock should have "property behavior",
meaning that setting its value will cause it to be saved and
later returned when the property is requested. (this is also
known as "stubbing"). The default value for each property will be the
one generated as specified by the property for the mock.
Just to update Arturo to be generic like your repository:
public Mock<IRepository<T>> MockRepository<T, TKey>() where T : BaseEntity<TKey> //(for Id )
{
var repository = new Mock<IRepository<T>>();
var entities = new List<T>(); // Add variables to be used in the setups
repository.Setup(x => x.GetAll()).Returns(entities.AsQueryable());
repository.Setup(x => x.GetById(It.IsAny<TKey>())).Returns<TKey>(id => entities.Find(c => c.Id == id));
repository.Setup(x => x.Add(It.IsAny<T>())).Callback<T>(c => entities.Add(c));
repository.Setup(x => x.Delete(It.IsAny<T>())).Callback<T>(c => entities.Remove(c));
...
return repository;
}

While, "basically" correct, the reason I cannot mark either of the given answers as correct is they didn't offer-up a "full" solution to the problem (e.g. the ability to reference custom properties for testing).
There may be a better way to do this, but here is what worked for me...
DESIRED OUTCOME:
Mock my UnitOfWork (using Moq)
Mock all Repositories in my UnitOfWork (using Moq)
Use fake-or-pseudo records from properties in the mocks (like a database)
Take actual database concerns OUT of the equation
The hope was to make our Unit Tests much more "clean & seamless"
ACTUAL OUTCOME:
It was a complete success
Our tests are EXTREMELY clean, seamless & easy to create (see below)
OUTLINE OF THE SOLUTION:
Create a MockBuilder for each Repository (using Moq)
Create a MockBuilder for UnitOfWork (using Moq)
Let calls to the Builder take away all the complexities for us
ORIGINAL REPOSITORY INTERFACE:
This is the interface all our repositories use. So, all our 'builders' had to Mock.Setup all of these for each repository.
public interface IRepository<TEntity> where TEntity : class
{
#region <Methods>
IQueryable<TEntity> GetActive();
IQueryable<TEntity> GetAll();
TEntity GetById(object id);
TEntity Find(params object[] keyValues);
void Add(TEntity entity);
void AddRange(IEnumerable<TEntity> entities);
void Update(TEntity entity);
void Delete(TEntity entity);
void Delete(object id);
void ApplyState(TEntity entity, EntityState state);
EntityState GetState(TEntity entity);
#endregion
}
BUILDER INTERFACE:
public interface IBuilder
{
// Marker interface
}
REPOSITORY MOCK BUILDER INTERFACE:
public interface IRepositoryMockBuilder<TEntity> : IBuilder where TEntity : class
{
List<TEntity> Entities { get; }
EntityState EntityState { get; }
Mock<IRepository<TEntity>> CreateMock();
}
CONCRETE REPOSITORY MOCK BUILDER:
public class ClaimRepositoryMockBuilder : IRepositoryMockBuilder<Claim>
{
#region <Constructor>
public ClaimRepositoryMockBuilder(bool autoSeed)
{
Entities = AutoSeed(autoSeed);
EntityState = EntityState.Unchanged;
}
#endregion
#region <Properties>
public List<Claim> Entities { get; private set; }
public EntityState EntityState { get; private set; }
#endregion
#region <Methods>
public Mock<IRepository<Claim>> CreateMock()
{
var repository = new Mock<IRepository<Claim>>();
repository.SetupAllProperties();
repository.Setup(x => x.GetActive()).Returns(this.Entities.AsQueryable());
repository.Setup(x => x.GetAll()).Returns(this.Entities.AsQueryable());
repository.Setup(x => x.GetById(It.IsAny<object>())).Returns((object id) => { return this.Entities.Where(e => e.ClaimId == id.ToString()).FirstOrDefault(); });
repository.Setup(x => x.Find(new object[] { It.IsAny<string>() })).Returns((object id) => { return this.Entities.Where(e => e.ClaimId == id.ToString()).FirstOrDefault(); });
repository.Setup(x => x.Add(It.IsAny<Claim>())).Callback<Claim>(x => { this.Entities.Add(x); }).Verifiable();
repository.Setup(x => x.AddRange(It.IsAny<IEnumerable<Claim>>())).Callback<IEnumerable<Claim>>(x => { this.Entities.AddRange(x); }).Verifiable();
repository.Setup(x => x.Update(It.IsAny<Claim>())).Callback<Claim>(x => { UpdateEntity(x); }).Verifiable();
repository.Setup(x => x.Delete(It.IsAny<Claim>())).Callback<Claim>(x => { DeleteByEntity(x); }).Verifiable();
repository.Setup(x => x.Delete(It.IsAny<object>())).Callback<object>(x => { DeleteById(x); }).Verifiable();
repository.Setup(x => x.ApplyState(It.IsAny<Claim>(), It.IsAny<EntityState>())).Callback<Claim, EntityState>((x, y) => { this.EntityState = y; }).Verifiable();
repository.Setup(x => x.GetState(It.IsAny<Claim>())).Returns((Claim claim) => { return this.EntityState; });
return repository;
}
#region private
private void DeleteById(object id)
{
var entity = this.Entities.FirstOrDefault(x => x.ClaimId == id.ToString());
if (entity != null)
this.Entities.RemoveAt(Entities.IndexOf(entity));
}
private void DeleteByEntity(Claim deletedEntity)
{
var entity = this.Entities.FirstOrDefault(x => x.ClaimId == deletedEntity.ClaimId);
if (entity != null)
this.Entities.Remove(entity);
}
private void UpdateEntity(Claim updatedEntity)
{
var entity = this.Entities.FirstOrDefault(x => x.ClaimId == updatedEntity.ClaimId);
if (entity != null)
entity = updatedEntity;
}
private List<Claim> AutoSeed(bool autoSeed)
{
if (!autoSeed)
return new List<Claim>();
var database = new List<Claim>();
database.Add(new Claim()
{
// Set Properties Here
});
database.Add(new Claim()
{
// Set Properties Here
});
database.Add(new Claim()
{
// Set Properties Here
});
return database;
}
#endregion
#endregion
}
CONCRETE UNIT-OF-WORK MOCK BUILDER:
Add as many properties as you have repositories (we have a TON)
public class UnitOfWorkMockBuilder : IBuilder
{
#region <Constructors>
public UnitOfWorkMockBuilder(bool autoSeed)
{
ClaimsRepositoryBuilder = new ClaimsRepositoryMockBuilder(autoSeed);
SomeOtherRepositoryBuilder = new SomeOtherRepositoryMockBuilder(autoSeed);
}
#endregion
#region <Properties>
public ClaimsRepositoryMockBuilder ClaimsRepositoryBuilder { get; set; }
public SomeOtherRepositoryMockBuilder SomeOtherRepositoryBuilder { get; set; }
#endregion
#region <Methods>
public Mock<IMyUnitOfWork> CreateMock()
{
var unitOfWork = new Mock<IMyUnitOfWork>();
var depClaimTransactionsRepository = ClaimTransactionsRepositoryBuilder.CreateMock();
var depSomeOtherRepository = SomeOtherRepository.CreateMock();
unitOfWork.SetupAllProperties();
unitOfWork.Object.Claim = depClaimsRepositoryBuilder.Object;
unitOfWork.Object.SomeOther = depSomeOtherRepository.Object;
return unitOfWork;
}
#endregion
}
THE RESULTING UNIT TEST:
This is just one test, but ALL of out tests GREATLY cleaned up as a result of this effort.
[TestClass]
public class ClaimExistsRuleUnitTest
{
[TestMethod]
public void Returns_IsBau_When_Claim_DoesNotExist()
{
var builderUnitOfWork = new UnitOfWorkMockBuilder(true);
var claimId = "666";
var process = "MyAwesomeProcess";
// -----
// ARRANGE
// -----
var depUnitOfWork = builderUnitOfWork.CreateMock().Object;
var depProcess = depUnitOfWork.Processes.GetAll().Where(x => x.FriendlyName == process).First();
var depClaimMessage = new ClaimMessage();
var mockValidationResult = null as IValidationResult;
depClaimMessage.ClaimId = claimId;
depClaimMessage.StpClaimRequestProcessId = depProcess.Stp_Process_Code_Id;
// -----
// ACT
// -----
var rule = new ClaimExistsRule();
rule.UnitOfWork = depUnitOfWork;
mockValidationResult = rule.Validate(depClaimMessage);
// -----
// ASSERT
// -----
Assert.AreEqual(ClaimAction.IsBAU, mockValidationResult.Action);
}
#endregion
}

Related

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);
}

Mocked method still returns null

In my new .Net Core project I decided to use Moq framework for a first time. After I set up all method according to tutorial I still getting Exception:
"The following setups were not matched:
IRepository`1 cr => cr.GetSingle(x => x.Key == 7028750f-044c-4862-999d-e21c4bfe7543) "
or after removing all VerifyAll() calls, a got null from serivice.
Any idea how to solve it?
Dependences:
"Microsoft.NETCore.App": "1.1.0",
"Moq": "4.6.38-alpha",
"xunit": "2.2.0-beta5-build3474",
"dotnet-test-xunit": "2.2.0-preview2-build1029",
Character:
public class Character : IEntity
{
...
public Guid Key { get; set; }
...
}
Generic repository:
public interface IRepository<TEntity> where TEntity : class, IEntity
{
TEntity GetSingle(Expression<Func<TEntity, bool>> predicate);
...
}
Unit of work:
public interface IUnitOfWork
{
IRepository<TEntity> Repository<TEntity>() where TEntity : class, IEntity;
...
}
Characters service:
class CharactersService : ICharactersService
{
private readonly IUnitOfWork _unitOfWork;
public CharactersService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public Character GetCharacterByKey(Guid characterKey)
{
var charactersRepository = _unitOfWork.Repository<Character>();
var character = charactersRepository.GetSingle(ch => ch.Key == characterKey);
return character;
}
...
}
Test class:
public class CharactersServiceTest
{
[Fact]
public void GetCharacterByKey_CharacterExists_ReturnsCharacter()
{
//Arrange
var guid = Guid.NewGuid();
var characterFromDb = new Character { Key = guid };
var characterRepositoryMock = new Mock<IRepository<Character>>();
characterRepositoryMock.Setup(cr => cr.GetSingle(x => x.Key == guid)).Returns(characterFromDb);
characterRepositoryMock.VerifyAll();
var unitOfWorkMock = new Mock<IUnitOfWork>();
unitOfWorkMock.Setup(uow => uow.Repository<Character>()).Returns(characterRepositoryMock.Object);
unitOfWorkMock.VerifyAll();
var charactersService = new CharactersService(unitOfWorkMock.Object);
//Act
var character = charactersService.GetCharacterByKey(guid);
//Assert
Assert.NotNull(character);
}
}
The problem here is, that you compare two expressions:
First in characterRepositoryMock.Setup : x => x.Key == guid
And the second one in GetCharacterByKey Method: ch => ch.Key == characterKey
They are not identical because they point to two different Expression objects.
If you really want to test it such way, you should check, that both expressions get the same GUID value:
characterRepositoryMock.Setup(cr =>
cr.GetSingle(It.Is<Expression<Func<Character, bool>>>(x =>check(x, guid)) ))
.Returns(characterFromDb);
With this check method:
public bool check(Expression<Func<Character,bool>> x, Guid guid)
{
var body = x.Body as BinaryExpression;
var g = (Guid) Expression.Lambda(body.Right).Compile().DynamicInvoke();
return g == guid;
}
And, yes i agree with comments, VerifyAll should be called after all, in Assert part.

Mocking dbset<T> where method returns notSupportedException

I'm trying to Mock the where clause of the dbset of my generic repository, and no idea why I'm getting a System.NotSupported Exception.
I'm quite new into mocking, so I have no clue why this is happening.
private List<StubEntity> _data;
private Repository<StubEntity> _repository;
[TestInitialize]
public void TestInitialize()
{
_data = new List<StubEntity>
{
new StubEntity {Id = 1, Name = "Entity 1"},
...
};
var queryableData = _data.AsQueryable();
var mockDbSet = new Mock<DbSet<StubEntity>>();
mockDbSet
.Setup(m => m.Where(It.IsAny<Expression<Func<StubEntity, bool>>>()))
.Returns<Expression<Func<StubEntity, bool>>>(p => queryableData.Where(p));
var context = new Mock<StubContext>();
context.Setup(x => x.DbEntities).Returns(mockDbSet.Object);
context.Setup(x => x.Set<StubEntity>()).Returns(mockDbSet.Object);
_repository = new Repository<StubEntity>(context.Object);
}
I'm only testing the where clause into a test
[TestMethod]
public void Find_ReturnsProperEntity()
{
var entity = _repository.Find(s => s.Id == 1);
....
}
where the Find method just call the where clause of the context.
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return Context.Set<TEntity>().Where(predicate);
}
Moq has issues with non-virtual members (methods/properties) and will throw exceptions when they are encountered.
eg:
System.NotSupportedException: System.NotSupportedException: Invalid
setup on a non-virtual (overridable in VB) member: x => x.DbEntities.
The assumption here is that your StubContext looks something like this...
public class StubContext : DbContext {
//...code removed for brevity
public DbSet<StubEntity> DbEntities { get; set; }
//...other code removed for brevity
}
...when it should be edited with a virtual property like...
public class StubContext : DbContext {
//...code removed for brevity
public virtual DbSet<StubEntity> DbEntities { get; set; }
//...other code removed for brevity
}
Using the following utility classes
using Moq;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
public static class MockDbSet {
public static Mock<DbSet<T>> Create<T>(params T[] elements) where T : class {
return elements.AsDbSetMock();
}
}
public static class MockDbSetExtensions {
public static Mock<DbSet<T>> AsDbSetMock<T>(this IEnumerable<T> list) where T : class {
IQueryable<T> queryableList = list.AsQueryable();
Mock<DbSet<T>> dbSetMock = new Mock<DbSet<T>>();
dbSetMock.As<IQueryable<T>>().Setup(x => x.Provider).Returns(queryableList.Provider);
dbSetMock.As<IQueryable<T>>().Setup(x => x.Expression).Returns(queryableList.Expression);
dbSetMock.As<IQueryable<T>>().Setup(x => x.ElementType).Returns(queryableList.ElementType);
dbSetMock.As<IQueryable<T>>().Setup(x => x.GetEnumerator()).Returns(() => queryableList.GetEnumerator());
return dbSetMock;
}
}
I recreated your unit test with a mocked DbSet and the suggested fix...
[TestClass]
public class MockDbSetTests {
private List<StubEntity> _data;
private Repository<StubEntity> _repository;
[TestInitialize]
public void TestInitialize() {
_data = new List<StubEntity>
{
new StubEntity {Id = 1, Name = "Entity 1"},
//...
};
var mockDbSet = _data.AsDbSetMock();
var context = new Mock<StubContext>();
context.Setup(x => x.DbEntities).Returns(mockDbSet.Object);
context.Setup(x => x.Set<StubEntity>()).Returns(mockDbSet.Object);
_repository = new Repository<StubEntity>(context.Object);
}
[TestMethod]
public void Find_Should_Return_Proper_Entity() {
//Act
var entity = _repository.Find(s => s.Id == 1);
//Assert
Assert.IsNotNull(entity);
Assert.IsTrue(entity.Count() == 1);
}
}
...and it passed (GREEN).

Mocking EF DbContext with Moq

I'm trying to create a unit test for my service with a mocked DbContext. I created an interface IDbContext with the following functions:
public interface IDbContext : IDisposable
{
IDbSet<T> Set<T>() where T : class;
DbEntityEntry<T> Entry<T>(T entity) where T : class;
int SaveChanges();
}
My real context implements this interface IDbContext and DbContext.
Now I'm trying to mock the IDbSet<T> in the context, so it returns a List<User> instead.
[TestMethod]
public void TestGetAllUsers()
{
// Arrange
var mock = new Mock<IDbContext>();
mock.Setup(x => x.Set<User>())
.Returns(new List<User>
{
new User { ID = 1 }
});
UserService userService = new UserService(mock.Object);
// Act
var allUsers = userService.GetAllUsers();
// Assert
Assert.AreEqual(1, allUsers.Count());
}
I always get this error on .Returns:
The best overloaded method match for
'Moq.Language.IReturns<AuthAPI.Repositories.IDbContext,System.Data.Entity.IDbSet<AuthAPI.Models.Entities.User>>.Returns(System.Func<System.Data.Entity.IDbSet<AuthAPI.Models.Entities.User>>)'
has some invalid arguments
I managed to solve it by creating a FakeDbSet<T> class that implements IDbSet<T>
public class FakeDbSet<T> : IDbSet<T> where T : class
{
ObservableCollection<T> _data;
IQueryable _query;
public FakeDbSet()
{
_data = new ObservableCollection<T>();
_query = _data.AsQueryable();
}
public virtual T Find(params object[] keyValues)
{
throw new NotImplementedException("Derive from FakeDbSet<T> and override Find");
}
public T Add(T item)
{
_data.Add(item);
return item;
}
public T Remove(T item)
{
_data.Remove(item);
return item;
}
public T Attach(T item)
{
_data.Add(item);
return item;
}
public T Detach(T item)
{
_data.Remove(item);
return item;
}
public T Create()
{
return Activator.CreateInstance<T>();
}
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
{
return Activator.CreateInstance<TDerivedEntity>();
}
public ObservableCollection<T> Local
{
get { return _data; }
}
Type IQueryable.ElementType
{
get { return _query.ElementType; }
}
System.Linq.Expressions.Expression IQueryable.Expression
{
get { return _query.Expression; }
}
IQueryProvider IQueryable.Provider
{
get { return _query.Provider; }
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return _data.GetEnumerator();
}
}
Now my test looks like this:
[TestMethod]
public void TestGetAllUsers()
{
//Arrange
var mock = new Mock<IDbContext>();
mock.Setup(x => x.Set<User>())
.Returns(new FakeDbSet<User>
{
new User { ID = 1 }
});
UserService userService = new UserService(mock.Object);
// Act
var allUsers = userService.GetAllUsers();
// Assert
Assert.AreEqual(1, allUsers.Count());
}
In case anyone is still interested, I was having the same problem and found this article very helpful:
Entity Framework Testing with a Mocking Framework (EF6 onwards)
It only applies to Entity Framework 6 or newer, but it covers everything from simple SaveChanges tests to async query testing all using Moq (and a few of manual classes).
Thank you Gaui for your great idea =)
I did add some improvements to your solution and want to share it.
My FakeDbSet also inherents from DbSet to get additional methods
like AddRange()
I replaced the ObservableCollection<T> with List<T> to pass all
the already implemented methods in List<> up to my FakeDbSet
My FakeDbSet:
public class FakeDbSet<T> : DbSet<T>, IDbSet<T> where T : class {
List<T> _data;
public FakeDbSet() {
_data = new List<T>();
}
public override T Find(params object[] keyValues) {
throw new NotImplementedException("Derive from FakeDbSet<T> and override Find");
}
public override T Add(T item) {
_data.Add(item);
return item;
}
public override T Remove(T item) {
_data.Remove(item);
return item;
}
public override T Attach(T item) {
return null;
}
public T Detach(T item) {
_data.Remove(item);
return item;
}
public override T Create() {
return Activator.CreateInstance<T>();
}
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T {
return Activator.CreateInstance<TDerivedEntity>();
}
public List<T> Local {
get { return _data; }
}
public override IEnumerable<T> AddRange(IEnumerable<T> entities) {
_data.AddRange(entities);
return _data;
}
public override IEnumerable<T> RemoveRange(IEnumerable<T> entities) {
for (int i = entities.Count() - 1; i >= 0; i--) {
T entity = entities.ElementAt(i);
if (_data.Contains(entity)) {
Remove(entity);
}
}
return this;
}
Type IQueryable.ElementType {
get { return _data.AsQueryable().ElementType; }
}
Expression IQueryable.Expression {
get { return _data.AsQueryable().Expression; }
}
IQueryProvider IQueryable.Provider {
get { return _data.AsQueryable().Provider; }
}
IEnumerator IEnumerable.GetEnumerator() {
return _data.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator() {
return _data.GetEnumerator();
}
}
It is very easy to modify the dbSet and Mock the EF Context Object:
var userDbSet = new FakeDbSet<User>();
userDbSet.Add(new User());
userDbSet.Add(new User());
var contextMock = new Mock<MySuperCoolDbContext>();
contextMock.Setup(dbContext => dbContext.Users).Returns(userDbSet);
Now it is possible to execute Linq queries, but be a aware that foreign key references may not be created automatically:
var user = contextMock.Object.Users.SingeOrDefault(userItem => userItem.Id == 42);
Because the context object is mocked the Context.SaveChanges() won't do anything and property changes of your entites might not be populated to your dbSet. I solved this by mocking my SetModifed() method to populate the changes.
Based on this MSDN article, I've created my own libraries for mocking DbContext and DbSet:
EntityFrameworkMock - GitHub
EntityFrameworkMockCore - GitHub
Both available on NuGet and GitHub.
The reason I've created these libraries is because I wanted to emulate the SaveChanges behavior, throw a DbUpdateException when inserting models with the same primary key and support multi-column/auto-increment primary keys in the models.
In addition, since both DbSetMock and DbContextMock inherit from Mock<DbSet> and Mock<DbContext>, you can use all features of the Moq framework.
Next to Moq, there also is an NSubstitute implementation.
Usage with the Moq version looks like this:
public class User
{
[Key, Column(Order = 0)]
public Guid Id { get; set; }
public string FullName { get; set; }
}
public class TestDbContext : DbContext
{
public TestDbContext(string connectionString)
: base(connectionString)
{
}
public virtual DbSet<User> Users { get; set; }
}
[TestFixture]
public class MyTests
{
var initialEntities = new[]
{
new User { Id = Guid.NewGuid(), FullName = "Eric Cartoon" },
new User { Id = Guid.NewGuid(), FullName = "Billy Jewel" },
};
var dbContextMock = new DbContextMock<TestDbContext>("fake connectionstring");
var usersDbSetMock = dbContextMock.CreateDbSetMock(x => x.Users, initialEntities);
// Pass dbContextMock.Object to the class/method you want to test
// Query dbContextMock.Object.Users to see if certain users were added or removed
// or use Mock Verify functionality to verify if certain methods were called: usersDbSetMock.Verify(x => x.Add(...), Times.Once);
}
If anyone is still looking for answers I've implemented a small library to allow mocking DbContext.
step 1
Install Coderful.EntityFramework.Testing nuget package:
Install-Package Coderful.EntityFramework.Testing
step 2
Then create a class like this:
internal static class MyMoqUtilities
{
public static MockedDbContext<MyDbContext> MockDbContext(
IList<Contract> contracts = null,
IList<User> users = null)
{
var mockContext = new Mock<MyDbContext>();
// Create the DbSet objects.
var dbSets = new object[]
{
MoqUtilities.MockDbSet(contracts, (objects, contract) => contract.ContractId == (int)objects[0] && contract.AmendmentId == (int)objects[1]),
MoqUtilities.MockDbSet(users, (objects, user) => user.Id == (int)objects[0])
};
return new MockedDbContext<SourcingDbContext>(mockContext, dbSets);
}
}
step 3
Now you can create mocks super easily:
// Create test data.
var contracts = new List<Contract>
{
new Contract("#1"),
new Contract("#2")
};
var users = new List<User>
{
new User("John"),
new User("Jane")
};
// Create DbContext with the predefined test data.
var dbContext = MyMoqUtilities.MockDbContext(
contracts: contracts,
users: users).DbContext.Object;
And then use your mock:
// Create.
var newUser = dbContext.Users.Create();
// Add.
dbContext.Users.Add(newUser);
// Remove.
dbContext.Users.Remove(someUser);
// Query.
var john = dbContext.Users.Where(u => u.Name == "John");
// Save changes won't actually do anything, since all the data is kept in memory.
// This should be ideal for unit-testing purposes.
dbContext.SaveChanges();
Full article: http://www.22bugs.co/post/Mocking-DbContext/
I'm late, but found this article helpful: Testing with InMemory (MSDN Docs).
It explains how to use an in memory DB context (which is not a database) with the benefit of very little coding and the opportunity to actually test your DBContext implementation.

EF6 Mocking derived DbSets

I am trying to apply the new mocking of EF6 to my existing code.
I have a class that Extends DbSet. One of the methods call the base class (BdSet) Create method. Here is the a sample code (not the complete solution or real names):
public class DerivedDbSet<TEntity> : DbSet<TEntity>, IKeyValueDbSet<TEntity>, IOrderedQueryable<TEntity> where TEntity : class
{
public virtual bool Add(string value1, string value2) {
var entity = Create(); // There is no direct implementation of the Create method it is calling the base method
// Do something with the values
this.Add(entity);
return true;
}
}
I am mocking using the Test Doubles sample (here is the peace of code):
var data = new List<DummyEntity> {
new DummyEntity { Value1 = "First", Value2 = "001" },
new DummyEntity { Value1 = "Second", Value2 = "002" }
}.AsQueryable();
var mock = new Mock<DerivedDbSet<DummyEntity>>();
mock.CallBase = true;
mock.As<IQueryable<T>>().Setup(m => m.Provider).Returns(source.Provider);
mock.As<IQueryable<T>>().Setup(m => m.Expression).Returns(source.Expression);
mock.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(source.ElementType);
mock.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(source.GetEnumerator());
I've set the CallBase property to true to try to force the call to the base class...
But I keep receiving the following error:
System.NotImplementedException: The member 'Create' has not been implemented on type 'DerivedDbSet1Proxy' which inherits from 'DbSet1'. Test doubles for 'DbSet`1' must provide implementations of methods and properties that are used.
I want the call of create to fallback to the default implementation in DbSet.
Can someone help me with that?
After some struggle with the internal functions and async references of mocking a DbSet I came out with a helper class that solved most of my problems and might serve as base to someone implementation.
Here is the code:
public static class MockHelper
{
internal class TestDbAsyncQueryProvider<TEntity> : IDbAsyncQueryProvider {
private readonly IQueryProvider _inner;
internal TestDbAsyncQueryProvider(IQueryProvider inner) { _inner = inner; }
public IQueryable CreateQuery(Expression expression) { return new TestDbAsyncEnumerable<TEntity>(expression); }
public IQueryable<TElement> CreateQuery<TElement>(Expression expression) { return new TestDbAsyncEnumerable<TElement>(expression); }
public object Execute(Expression expression) { return _inner.Execute(expression); }
public TResult Execute<TResult>(Expression expression) { return _inner.Execute<TResult>(expression); }
public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken) { return Task.FromResult(Execute(expression)); }
public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken) { return Task.FromResult(Execute<TResult>(expression)); }
}
internal class TestDbAsyncEnumerable<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T> {
public TestDbAsyncEnumerable(IEnumerable<T> enumerable) : base(enumerable) { }
public TestDbAsyncEnumerable(Expression expression) : base(expression) { }
public IDbAsyncEnumerator<T> GetAsyncEnumerator() { return new TestDbAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator()); }
IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator() { return GetAsyncEnumerator(); }
public IQueryProvider Provider { get { return new TestDbAsyncQueryProvider<T>(this); } }
}
internal class TestDbAsyncEnumerator<T> : IDbAsyncEnumerator<T> {
private readonly IEnumerator<T> _inner;
public TestDbAsyncEnumerator(IEnumerator<T> inner) { _inner = inner; }
public void Dispose() { _inner.Dispose(); }
public Task<bool> MoveNextAsync(CancellationToken cancellationToken) { return Task.FromResult(_inner.MoveNext()); }
public T Current { get { return _inner.Current; } }
object IDbAsyncEnumerator.Current { get { return Current; } }
}
public static Mock<TDbSet> CreateDbSet<TDbSet, TEntity>(IList<TEntity> data, Func<object[], TEntity> find = null)
where TDbSet : class, IDbSet<TEntity>
where TEntity : class, new() {
var source = data.AsQueryable();
var mock = new Mock<TDbSet> { CallBase = true };
mock.As<IQueryable<TEntity>>().Setup(m => m.Expression).Returns(source.Expression);
mock.As<IQueryable<TEntity>>().Setup(m => m.ElementType).Returns(source.ElementType);
mock.As<IQueryable<TEntity>>().Setup(m => m.GetEnumerator()).Returns(source.GetEnumerator());
mock.As<IQueryable<TEntity>>().Setup(m => m.Provider).Returns(new TestDbAsyncQueryProvider<TEntity>(source.Provider));
mock.As<IDbAsyncEnumerable<TEntity>>().Setup(m => m.GetAsyncEnumerator()).Returns(new TestDbAsyncEnumerator<TEntity>(data.GetEnumerator()));
mock.As<IDbSet<TEntity>>().Setup(m => m.Create()).Returns(new TEntity());
mock.As<IDbSet<TEntity>>().Setup(m => m.Add(It.IsAny<TEntity>())).Returns<TEntity>(i => { data.Add(i); return i; });
mock.As<IDbSet<TEntity>>().Setup(m => m.Remove(It.IsAny<TEntity>())).Returns<TEntity>(i => { data.Remove(i); return i; });
if (find != null) mock.As<IDbSet<TEntity>>().Setup(m => m.Find(It.IsAny<object[]>())).Returns(find);
return mock;
}
public static Mock<DbSet<TEntity>> CreateDbSet<TEntity>(IList<TEntity> data, Func<object[], TEntity> find = null)
where TEntity : class, new() {
return CreateDbSet<DbSet<TEntity>, TEntity>(data, find);
}
}
And here is a use sample (based on the names I've given before):
var data = new List<DummyEntity> {
new DummyEntity { Value1 = "First", Value2 = "001" } },
new DummyEntity { Value1 = "Second", Value2 = "002" } }
};
var mockDummyEntities = MockHelper.CreateDbSet<DerivedDbSet<DummyEntities>, DummyEntities>(data, i => data.FirstOrDefault(k => k.Value2 == (string)i[0]));
var mockContext = new Mock<DummyDbContext>();
mockContext.Setup(c => c.DummyEntities).Returns(mockDummyEntities.Object);
Any suggestions on how to improve this solution is very welcome.
Regards
This is a modified version based on Andre that worked for me. Note, that I did not need the async references. Code will add all derived classes (if any)
Usage:
/// <summary>
///
/// </summary>
[TestMethod]
public void SomeTest()
{
//Setup
var mockContext = new Mock<FakeDbContext>();
//SomeClass can be abstract or concrete
mockContext.createFakeDBSet<SomeClass>();
var db = mockContext.Object;
//Setup create(s) if needed on concrete classes
//Mock.Get(db.Set<SomeOtherClass>()).Setup(x => x.Create()).Returns(new SomeOtherClass());
//DO Stuff
var list1 = db.Set<SomeClass>().ToList();
//SomeOtherClass derived from SomeClass
var subList1 = db.Set<SomeOtherClass>().ToList();
CollectionAssert.AreEquivalent(list1.OfType<SomeOtherClass>.ToList(), subList1);
}
Code:
/// <summary>
/// http://stackoverflow.com/questions/21943328/ef6-mocking-derived-dbsets
/// </summary>
public static class MoqSetupExtensions
{
static IEnumerable<Type> domainTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes());
public static Mock<DbSet<T>> createFakeDBSet<T>(this Mock<FakeDbContext> db, List<T> list = null, Func<List<T>, object[], T> find = null, bool createDerivedSets = true) where T : class
{
list = list ?? new List<T>();
var data = list.AsQueryable();
//var mockSet = MockHelper.CreateDbSet(list, find);
var mockSet = new Mock<DbSet<T>>() { CallBase = true };
mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(() => { return data.Provider; });
mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(() => { return data.Expression; });
mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(() => { return data.ElementType; });
mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => { return list.GetEnumerator(); });
mockSet.Setup(m => m.Add(It.IsAny<T>())).Returns<T>(i => { list.Add(i); return i; });
mockSet.Setup(m => m.AddRange(It.IsAny<IEnumerable<T>>())).Returns<IEnumerable<T>>((i) => { list.AddRange(i); return i; });
mockSet.Setup(m => m.Remove(It.IsAny<T>())).Returns<T>(i => { list.Remove(i); return i; });
if (find != null) mockSet.As<IDbSet<T>>().Setup(m => m.Find(It.IsAny<object[]>())).Returns<object[]>((i) => { return find(list, i); });
//mockSet.Setup(m => m.Create()).Returns(new T());
db.Setup(x => x.Set<T>()).Returns(mockSet.Object);
//Setup all derived classes
if (createDerivedSets)
{
var type = typeof(T);
var concreteTypes = domainTypes.Where(x => type.IsAssignableFrom(x) && type != x).ToList();
var method = typeof(MoqSetupExtensions).GetMethod("createFakeDBSetSubType");
foreach (var item in concreteTypes)
{
var invokeResult = method.MakeGenericMethod(type, item)
.Invoke(null, new object[] { db, mockSet });
}
}
return mockSet;
}
public static Mock<DbSet<SubType>> createFakeDBSetSubType<BaseType, SubType>(this Mock<FakeDbContext> db, Mock<DbSet<BaseType>> baseSet)
where BaseType : class
where SubType : class, BaseType
{
var dbSet = db.Object.Set<BaseType>();
var mockSet = new Mock<DbSet<SubType>>() { CallBase = true };
mockSet.As<IQueryable<SubType>>().Setup(m => m.Provider).Returns(() => { return dbSet.OfType<SubType>().Provider; });
mockSet.As<IQueryable<SubType>>().Setup(m => m.Expression).Returns(() => { return dbSet.OfType<SubType>().Expression; });
mockSet.As<IQueryable<SubType>>().Setup(m => m.ElementType).Returns(() => { return dbSet.OfType<SubType>().ElementType; });
mockSet.As<IQueryable<SubType>>().Setup(m => m.GetEnumerator()).Returns(() => { return dbSet.OfType<SubType>().GetEnumerator(); });
mockSet.Setup(m => m.Add(It.IsAny<SubType>())).Returns<SubType>(i => { dbSet.Add(i); return i; });
mockSet.Setup(m => m.AddRange(It.IsAny<IEnumerable<SubType>>())).Returns<IEnumerable<SubType>>((i) => { dbSet.AddRange(i); return i; });
mockSet.Setup(m => m.Remove(It.IsAny<SubType>())).Returns<SubType>(i => { dbSet.Remove(i); return i; });
mockSet.As<IDbSet<SubType>>().Setup(m => m.Find(It.IsAny<object[]>())).Returns<object[]>((i) => { return dbSet.Find(i) as SubType; });
baseSet.Setup(m => m.Create<SubType>()).Returns(() => { return mockSet.Object.Create(); });
db.Setup(x => x.Set<SubType>()).Returns(mockSet.Object);
return mockSet;
}
}
Microsoft published a very well explained guide providing an in-memory implementation of DbSet which has a complete implemention for all the methods on DbSet.
Check the article at http://msdn.microsoft.com/en-us/data/dn314431.aspx#doubles

Categories

Resources