I have a service let's say Foo service class.
public class FooService : IFooService
{
private readonly IFooRepository _repository;
private readonly ISomeService _eventService;
public FooService(IFooRepository repository, ISomeService eventService)
{
_repository = repository;
_someService = someService;
}
public IReadOnlyCollection<Foo> GetFoos(bool isDeleted = true)
{
var foos= _repository.GetList(x => x.IsDeleted == isDeleted).ToList();
return !foos.Any() ? new List<Foo>(): foos;
}
}
Here is IFooRepository
public interface IFooRepository : IGenericRepository<Foo>
{
}
and here is IGenericRepository
public interface IGenericRepository<T> where T: BaseEntity
{
IReadOnlyCollection<T> GetList(Expression<Func<T, bool>> where, params Expression<Func<T, object>>[] nav);
}
In my test I want to verify that FooService's GetFoos method calls GetList method
This is what I tried
[TestClass]
public class FooServiceTest
{
private IQueryable<Foo> _foos;
private Mock<IFooRepository> _fooRepository;
private FooService _fooService;
private Mock<ISomeService> _someService;
[TestInitialize]
public void SetUp()
{
_foos = new List<Foo>
{
new Foo
{
EmailId = "a#a.com",
IsDeleted = false,
},
new Foo
{
EmailId = "a#a.com",
IsDeleted = true,
},
}.AsQueryable();
}
[TestMethod]
public void GetGetFoos_CallsGetList()
{
//Arrange
var foos= _foos.Where(x => x.IsDeleted).ToList();
_fooRepository = new Mock<IFooRepository>();
_fooRepository.Setup(m => m.GetList(x => x.IsDeleted)).Returns(foos);
_someServiceMock = new Mock<ISomeService>();
_fooService = new FooService(_fooRepository.Object, _someServiceMock.Object);
//Act
_fooService.GetFoos(true);
//Assert
_fooRepository.Verify(m=>m.GetList(x=>x.IsDeleted), Times.Once());
}
}
But I get argument null exception in following line
var foos= _repository.GetList(x => x.IsDeleted == isDeleted).ToList();
Any clue why this is happening even though I am saying Returns(foos) during setup.
Also how do I verify the interface method was called?
What is happening (most likely) is Moq can't match Expression<Func<T, bool>> when you do the .Setup().
So instead you can use IsAny<>() approach:
_fooRepository.Setup(m => m.GetList(It.IsAny<Expression<Func<Foo, bool>>>())).Returns(foos);
If you want to assert what expression is passed in, try
Expression<Func<Foo, bool>> capturedExpression = null;
_fooRepository.Setup(m => m.GetList(It.IsAny<Expression<Func<Foo, bool>>>()))
.Returns((Expression<Func<Foo, bool>> e ) => { capturedExpression = e; return foos; });
Assert.IsTrue(capturedExpression.Compile()(_foos[1]));
Assert.IsFalse(capturedExpression.Compile()(_foos[0]));
to verify the method was called you can also change the last it a bit more:
_fooRepository.Setup(m => m.GetList(It.IsAny<Expression<Func<Foo, bool>>>()))
.Returns((Expression<Func<Foo, bool>> e ) => { capturedExpression = e; return foos; })
.Verifiable();
then _fooRepository.Verify(m=>m.GetList(It.IsAny<Expression<Func<Foo, bool>>>()), Times.Once()); However, if it is not called, then capturedExpression is null (that technique is known as implicit assertion)
Related
I've been trying to unit test this simple method:
public void DeleteAllSettingsLinkedToSoftware(Guid softwareId)
{
_dbContext.Settings.Where(s => s.SoftwareId == softwareId).ForEachAsync(s => s.IsDeleted = true);
_dbContext.SaveChanges();
}
However I'm having a hard time unit testing this method from the moment the ForEachAsync() method gets called.
So far I've used Moq to setup the dbContext to return the proper settings when the Where() is executed.
My attempt:
Setup(m => m.ForEachAsync(It.IsAny<Action<Setting>>(), CancellationToken.None));
My question is: How will I unit test the call to the ForEachAsync() method?
I've read online that some people say it's impossible to unit test some static methods, if that's true in my case I'm curious about alternatives to test as much of this method as possible.
Edit
My complete test code:
[TestMethod]
public async Task DeleteAllSettingsLinkedToSoftware_Success()
{
//Arrange
var settings = new List<Setting>
{
new Setting
{
SoftwareId = SoftwareId1
},
new Setting
{
SoftwareId = SoftwareId1
},
new Setting
{
SoftwareId = SoftwareId1
},
new Setting
{
SoftwareId = SoftwareId2
}
}.AsQueryable();
var queryableMockDbSet = GetQueryableMockDbSet(settings.ToList());
queryableMockDbSet.As<IQueryable<Setting>>()
.Setup(m => m.Provider)
.Returns(new TestDbAsyncQueryProvider<Setting>(settings.Provider));
DbContext.Setup(m => m.Settings).Returns(queryableMockDbSet.Object);
_settingData = new SettingData(DbContext.Object, SettingDataLoggerMock.Object);
//Act
var result = await _settingData.DeleteAllSettingsLinkedToSoftwareAsync(SoftwareId1);
//Assert
DbContext.Verify(m => m.Settings);
DbContext.Verify(m => m.SaveChanges());
Assert.AreEqual(4, DbContext.Object.Settings.Count());
Assert.AreEqual(SoftwareId2, DbContext.Object.Settings.First().SoftwareId);
}
I am aware that my Assert still needs more checks.
The GetQueryableMockDbSet method:
public static Mock<DbSet<T>> GetQueryableMockDbSet<T>(List<T> sourceList) where T : class
{
var queryable = sourceList.AsQueryable();
var dbSet = new Mock<DbSet<T>>();
dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());
dbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>(s => sourceList.Add(s));
dbSet.Setup(d => d.AddRange(It.IsAny<IEnumerable<T>>())).Callback<IEnumerable<T>>(sourceList.AddRange);
dbSet.Setup(d => d.Remove(It.IsAny<T>())).Callback<T>(s => sourceList.Remove(s));
dbSet.Setup(d => d.RemoveRange(It.IsAny<IEnumerable<T>>())).Callback<IEnumerable<T>>(s =>
{
foreach (var t in s.ToList())
{
sourceList.Remove(t);
}
});
return dbSet;
}
You don't have to mock ForEachAsync at all. ForEachAsync returns Task and is being execute asynchronously this is the source of your problem.
Use async and await keywards to solve your problem:
public async void DeleteAllSettingsLinkedToSoftware(Guid softwareId)
{
await _dbContext.Settings.Where(s => s.SoftwareId == softwareId)
.ForEachAsync(s => s.IsDeleted = true);
_dbContext.SaveChanges();
}
Edit:
The new exception occurs because the supplied Provider is not a IDbAsyncQueryProvider.
Microsoft implemented a generic version of this interface: TestDbAsyncQueryProvider<TEntity>. Here is the implementation from the link:
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>, IQueryable<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();
}
IQueryProvider IQueryable.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; }
}
}
Now in the Setup you'll have to use it like:
mockSet.As<IQueryable<Setting>>()
.Setup(m => m.Provider)
.Returns(new TestDbAsyncQueryProvider<Setting>(data.Provider));
Disclaimer: I won't provide a direct solution, as requested by OP because I believe this question is a XY problem. Instead I will focus my answer on why is this code so damn hard to test, because yes, more than 30 lines of "arrange" to test 2 lines of code means that something went very wrong.
Short answer
This method doesn't need to be tested, at least at the unit level.
Long answer
The problem with the current implementation is a mix of concern.
The first line: _dbContext.Settings.Where(s => s.SoftwareId == softwareId).ForEachAsync(s => s.IsDeleted = true); contains business logic (s.softwareId == softwareId, s.IsDeleted = true) but also EF logic (_dbContext, ForEachAsync).
The second line: _dbContext.SaveChanges(); contains only EF logic
The point is: such methods (that mix concerns) are hard to test at the unit level. Hence the fact you need mocks and several dozens of "Arrange" code to test only 2 lines of implementation !
Based on this constatation you have 2 options:
You delete your test because the method is mainly containing EF logic which is useless to test (see this great series of articles for more details)
You extract business logic and write a real (and simple) unit test
In the second case, I would implement this logic so that I would be able to write a test like that:
[Test]
public void ItShouldMarkCorrespondingSettingsAsDeleted()
{
var setting1 = new Setting(guid1);
var setting2 = new Setting(guid2);
var settings = new Settings(new[] { setting1, setting2 });
settings.DeleteAllSettingsLinkedToSoftware(guid1);
Assert.That(setting1.IsDeleted, Is.True);
Assert.That(setting1.IsDeleted, Is.False);
}
Easy to write, easy to read.
How about the implementation now ?
public interface ISettings
{
void DeleteAllSettingsLinkedToSoftware(Guid softwareId);
}
public sealed class Settings : ISettings
{
private readonly IEnumerable<Setting> _settings;
public Settings(IEnumerable<Setting> settings) => _settings = settings;
public override void DeleteAllSettingsLinkedToSoftware(Guid softwareGuid)
{
foreach(var setting in _settings.Where(s => s.SoftwareId == softwareId))
{
setting.IsDeleted = true;
}
}
}
public sealed class EFSettings : ISettings
{
private readonly ISettings _source;
private readonly DBContext _dbContext;
public EFSettings(DBContext dbContext)
{
_dbContext = dbContext;
_source = new Settings(_dbContext.Settings);
}
public override void DeleteAllSettingsLinkedToSoftware(Guid softwareGuid)
{
_source.DeleteAllSettingsLinkedToSoftware(softwareGuid);
_dbContext.SaveChanges();
}
}
With a solution like this, each concern is separated which allows to:
Get rid of mocks
Really unit test business-logic code
Gain in maintainability and readability
Hi I am trying to mock the following thing:
var result = _scope.Execute<FooService, IList<FooEntity>>(x => x.GetFooEntities(fooModel));
This is how I try to mock it:
_mockedScope
.Setup(x => x.Execute<FooService, IList<FooEntity>>(f => f.GetFooEntities(It.IsAny<FooModel>())))
.Returns(new List<FooEntity>)
But when I run the test it throws me an exception
Unsupported expression: s => s.GetFooEntities(IsAny())
Any suggestions how can I mock it?
Here is an example what i want to moq
public class Test
{
private readonly IScope _scope;
public Test(IScope scope)
{
_scope = scope;
}
public void Foo()
{
var foo = new FooEntity();
Result<IList<Foo>> result =
_scope.Execute<FooService, IList<Foo>>(
"f",
s => s.GetFoo(foo));
}
}
public class Foo
{
}
public class FooEntity
{
}
public class FooService
{
public List<Foo> GetFoo(FooEntity f);
}
public interface IScope
{
Result<TResult> Execute<T1, TResult>(string temp, Func<T1, TResult> function);
}
public class Result<T>
{
private Result(T value, Exception exception)
{
Value = value;
Error = exception;
}
public Exception Error { get; }
public T Value { get; }
public bool HasError => Error != null;
public static Result<T> Fail(Exception exception) => new Result<T>(default(T), exception);
public static Result<T> Success(T value) => new Result<T>(value, null);
}
While expressions are used by moq to setup mocks, you are trying to mock an expression. This tends to be very difficult with Moq but there are workarounds via matched arguments.
Assuming Scope.Execute method is defined like
public interface IScope {
Result<TResult> Execute<T, TResult>(string temp, Func<T, TResult> function);
}
Use It.IsAny to allow for flexibility when setting up a mock that relies on an expression argument.
_mockedScope
.Setup(x => x.Execute<FooService, IList<Foo>>(It.IsAny<string>(), It.IsAny<Func<FooService, IList<Foo>>>()))
.Returns(Result<IList<Foo>>.Success(new List<Foo>()));
The It.IsAny<Func<FooService, IList<Foo>>>() will cover s => s.GetFoo(foo) in the invoked code.
Given
public class Test {
private readonly IScope _scope;
public Test(IScope scope) {
_scope = scope;
}
public IList<Foo> Foo() {
var foo = new FooEntity();
Result<IList<Foo>> result = _scope.Execute<FooService, IList<Foo>>("f", s => s.GetFoo(foo));
var value = result.Value;
return value;
}
}
The following complete example was used to demonstrate what was explained above
[TestClass]
public class ExpressionMock {
[TestMethod]
public void TestFoo() {
//Arrange
var _mockedScope = new Mock<IScope>();
_mockedScope
.Setup(x => x.Execute<FooService, IList<Foo>>(It.IsAny<string>(), It.IsAny<Func<FooService, IList<Foo>>>()))
.Returns(Result<IList<Foo>>.Success(new List<Foo>()));
var subject = new Test(_mockedScope.Object);
//Act
var actual = subject.Foo();
//Assert
actual.Should().NotBeNull();
}
}
Reference Moq Quickstart to get a better understanding of how to use the framework
This question already has answers here:
Moq DbSet NotImplementedException
(2 answers)
Closed 5 years ago.
I want to do unit tests for that generic repository pattern, I have tried it in various ways and I can not get it, the closest thing to do is this here I leave the implementation that I have done
public abstract class Repository<TEntity, TKey> : IRepository<TEntity, TKey> where TEntity : Entity<TKey>
{
private readonly ValcalContext _context;
private readonly IUnitOfWork _unitOfWork;
public IUnitOfWork UnitOfWork => _unitOfWork;
public Repository(IUnitOfWork uow)
{
_context = uow.Context as ValcalContext;
_unitOfWork = uow;
}
public List<TEntity> All => _context.Set<TEntity>().ToList();
public List<TEntity> AllEager(params Expression<Func<TEntity, object>>[] includes)
{
IQueryable<TEntity> query = _context.Set<TEntity>();
foreach (var include in includes)
{
query = query.Include(include);
}
return query.ToList();
}
public TEntity Find(TKey id)
{
return _context.Set<TEntity>().Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return _context.Set<TEntity>().ToList();
}
public void Insert(TEntity item)
{
_context.Entry(item).State = EntityState.Added;
}
public void Delete(TEntity entity)
{
var item = _context.Set<TEntity>().Find(entity.Id);
_context.Set<TEntity>().Remove(item);
}
public void Delete(TKey id)
{
var item = _context.Set<TEntity>().Find(id);
_context.Set<TEntity>().Remove(item);
}
public void Update(TEntity item)
{
_context.Set<TEntity>().Attach(item);
_context.Entry(item).State = EntityState.Modified;
}
public void Dispose()
{
if (_context != null)
_context.Dispose();
}
}
This is my dbContext
public class ValcalContext : DbContext,IValcalContext
{
public ValcalContext() : base("ValcalConnection")
{
}
public static ValcalContext Create()
{
return new ValcalContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
AddConventions(modelBuilder);
var typesToRegister = TypesToRegister();
AddConfigurationsMapping(modelBuilder, typesToRegister);
base.OnModelCreating(modelBuilder);
}
#region Private Methods
/// <summary>
/// /Agrega las convenciones de mapeo a la base de dato
/// </summary>
/// <param name="modelBuilder"></param>
private void AddConventions(DbModelBuilder modelBuilder)
{
modelBuilder.Types().Configure(entity => entity.ToTable(entity.ClrType.Name.ToLowerUnderscored()));
modelBuilder.Conventions.Add(new UnderScoredLowerCaseConvention());
}
private static IEnumerable<Type> TypesToRegister()
{
var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => !string.IsNullOrEmpty(type.Namespace))
.Where(type => type.BaseType != null && type.BaseType.IsGenericType
&& type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
return typesToRegister;
}
private static void AddConfigurationsMapping(DbModelBuilder modelBuilder, IEnumerable<Type> typesToRegister)
{
foreach (var configurationInstance in typesToRegister.Select(Activator.CreateInstance))
{
modelBuilder.Configurations.Add((dynamic)configurationInstance);
}
}
#endregion
}
I want to do unit tests for that generic repository pattern,for now I have this
[TestClass]
public class RepositoryUnitTest
{
[TestMethod]
public void Sample()
{
//arrange
var mockEntityTest = new Mock<DbSet<EntityTest>>();
var unitOfWork = new Mock<IUnitOfWork>();
var valcalContext = new Mock<ValcalContext>();
valcalContext.Setup(vc => vc.Set<EntityTest>()).Returns(mockEntityTest.Object);
var mock = valcalContext.Object;
unitOfWork.Setup(uow => uow.Context).Returns(mock);
var repository = new RepositoryTest(unitOfWork.Object);
//act
var entityTests = repository.All;
//assert
Assert.AreEqual(entityTests.ToList().Count,0);
}
}
public class RepositoryTest : Repository<EntityTest, int>
{
public RepositoryTest(IUnitOfWork uow) : base(uow)
{
}
}
public class EntityTest : Entity<int>
{
}
but I get this error
I hope you can help me, I've been here for two hours
The member 'IEnumerable.GetEnumerator' has not been
implemented on type 'DbSet1Proxy' which inherits from 'DbSet1'. Test
doubles for 'DbSet`1' must provide implementations of methods and
properties that are used.
This error is different from this post Moq DbSet NotImplementedException
I just tried that solution and I'm still in the same
Really what I did was the following to make it clear
I uploaded the moq version for 4.8
I change this
[TestMethod]
public void Sample()
{
//arrange
var mockEntityTest = new Mock<DbSet<EntityTest>>();
var unitOfWork = new Mock<IUnitOfWork>();
var valcalContext = new Mock<ValcalContext>();
valcalContext.Setup(vc => vc.Set<EntityTest>()).Returns(mockEntityTest.Object);
var mock = valcalContext.Object;
unitOfWork.Setup(uow => uow.Context).Returns(mock);
var repository = new RepositoryTest(unitOfWork.Object);
//act
var entityTests = repository.All;
//assert
Assert.AreEqual(entityTests.ToList().Count,0);
}
for this
[TestMethod]
public void Sample()
{
//arrange
var mockEntityTest = new Mock<DbSet<EntityTest>>();
var list = new List<EntityTest>();
var queryable = list.AsQueryable();
mockEntityTest.As<IQueryable<EntityTest>>().Setup(m => m.Provider).Returns(queryable.Provider);
mockEntityTest.As<IQueryable<EntityTest>>().Setup(m => m.Expression).Returns(queryable.Expression);
mockEntityTest.As<IQueryable<EntityTest>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
mockEntityTest.As<IQueryable<EntityTest>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());
var unitOfWork = new Mock<IUnitOfWork>();
var valcalContext = new Mock<ValcalContext>();
valcalContext.Setup(vc => vc.Set<EntityTest>()).Returns(mockEntityTest.Object);
var mock = valcalContext.Object;
unitOfWork.Setup(uow => uow.Context).Returns(mock);
var repository = new RepositoryTest(unitOfWork.Object);
//act
var entityTests = repository.All;
//assert
Assert.AreEqual(entityTests.ToList().Count,0);
}
and it worked, that can be done generically as explained in this post How do I go about unit testing with Entity Framework and Moq? 45558663 # 45558663
but the essence of what I did was that.
Method to unit test: GetUserInfo
Following is the class containing the method:
public class AccountService : IAccountService
{
IUnitOfWork _UnitOfWork;
public AccountService(IUnitOfWork unitOfWork)
{
_UnitOfWork = unitOfWork;
}
public UserInfo GetUserInfo(string userName, string password)
{
var userInfo = new UserInfo();
userInfo.UserType = UserType.Invalid;
// Statement of interest
var portalUser = _UnitOfWork.Repository<DvaPortalUser>().Query().Filter(t => t.Email == userName && t.Password == password).Get().FirstOrDefault();
//....Rest of the code is not included for clarity
}
}
The interface to mock IUnitOfWork:
public interface IUnitOfWork
{
void Dispose();
void Save();
void Dispose(bool disposing);
IRepository<T> Repository<T>() where T : class;
}
Repository Implementation:
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
public virtual RepositoryQuery<TEntity> Query()
{
var repositoryGetFluentHelper = new RepositoryQuery<TEntity>(this);
return repositoryGetFluentHelper;
}
internal IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>,
IOrderedQueryable<TEntity>> orderBy = null,
List<Expression<Func<TEntity, object>>>
includeProperties = null,
int? page = null,
int? pageSize = null)
{
IQueryable<TEntity> query = DbSet;
if (includeProperties != null)
includeProperties.ForEach(i => query.Include(i));
if (filter != null)
query = query.Where(filter);
if (orderBy != null)
query = orderBy(query);
if (page != null && pageSize != null)
query = query
.Skip((page.Value - 1)*pageSize.Value)
.Take(pageSize.Value);
return query.ToList();
}
}
RepositoryQuery Implementation:
public sealed class RepositoryQuery<TEntity> where TEntity : class
{
private readonly List<Expression<Func<TEntity, object>>> _includeProperties;
private readonly Repository<TEntity> _repository;
private Expression<Func<TEntity, bool>> _filter;
private Func<IQueryable<TEntity>,
IOrderedQueryable<TEntity>> _orderByQuerable;
private int? _page;
private int? _pageSize;
public RepositoryQuery(Repository<TEntity> repository)
{
_repository = repository;
_includeProperties = new List<Expression<Func<TEntity, object>>>();
}
public RepositoryQuery<TEntity> Filter(Expression<Func<TEntity, bool>> filter)
{
_filter = filter;
return this;
}
public IEnumerable<TEntity> Get()
{
return _repository.Get(
_filter,
_orderByQuerable, _includeProperties, _page, _pageSize);
}
}
Unit Test Method:
[TestMethod]
public void AccountService_GetUserInfo_SuccessfulLogin()
{
var _UnitOfWork = new Mock<IUnitOfWork>();
_AccountService = new AccountService(_UnitOfWork.Object);
_UnitOfWork.Setup(a => a.Repository<T>())).Returns(??); //How do I setup this statement?
_UnitOfWork.VerifyAll();
}
Question: How do I setup mock call for the statement _UnitOfWork.Repository()?
I dont know how your IRepository<T> is implemented, but i gues your Query method returns a IEnumerable<T> or a list.
internal interface IRepository<T>
{
IEnumerable<T> Query();
}
// your mock
_UnitOfWork.Setup(a => a.Repository<DvaPortalUser>())).Returns(() => new MyTestRepository());
1. Solution
Define a explicit implemtation of you repository.
// your implementation
public class MyTestRepository : IRepository<DvaPortalUser>
{
public IEnumerable<DvaPortalUser> Query()
{
// return some test users (mocks)
return new List<DvaPortalUser> {new DvaPortalUser(), new DvaPortalUser()};
}
}
2. Solution (thanks to Yuliam Chandra)
Define a mock instead of the implemtation
var repository = new Mock<IRepository<DvaPortalUser>>();
// return some test users (mocks)
repository.Setup(a => a.Query()).Returns(new[] { new DvaPortalUser() });
_UnitOfWork.Setup(a => a.Repository<DvaPortalUser>()).Returns(repository.Object);
What you choose depends on your solution.
I'm trying to write a unit test for a method which looks like this:
public int Save(IEnumerable<int> addedIds, IEnumerable<int> removedIds)
{
var existingIds = repository.Get();
IEnumerable<int> ids = existingIds.Except(removedIds).Union(addedIds));
return repository.Create(ids);
}
The test in Moq looks like this:
repository.Setup(r => r.Get()).Returns(CreateList());
service.Save(addedIds, removedIds);
repository.Verify(r => r.Create(It.Is<IEnumerable<int>>(l => VerifyList(l))));
This fails, with this error, and VerifyList() is never called:
Expected invocation on the mock at least once, but was never
performed:
r => r.Create(It.Is<IEnumerable'1>(list => VerifyList(list)))
Performed invocations:
IRepo.Create(System.Linq.Enumerable+<UnionIterator>d__88'1[System.Int32])
As the invoked type is not IEnumerable<int> but is in fact System.Linq.Enumerable+<UnionIterator>d__88'1[System.Int32]), the test fails. (Stepping through the test, everything is happening correctly and the results are as expected)
If I call ids.ToList() in the method under test, these are the results:
Expected invocation on the mock at least once, but was never performed:
r => r.Create(It.Is<List'1>(l => VerifyList(l)))
Performed invocations:
IRepo.Create(System.Collections.Generic.List'1[System.Int32])
Is there any way round this? Or am I doing something wrong?
Edit: it turns out I had a mistake in my VerifyList method so it was returning false, but Moq wasn't giving me that information. The type difference is a red herring..
This seems to work. Made some assumptions though. Guess the VerifyList method could be better. =)
[Test]
public void Test()
{
// SETUP
Mock<IRepository> repository = new Mock<IRepository>();
Service service = new Service(repository.Object);
repository.Setup(r => r.Get()).Returns(CreateList());
IEnumerable<int> addedIds = new[]{1,2};
IEnumerable<int> removedIds = new[]{3,4};
service.Save(addedIds, removedIds);
repository.Verify(r => r.Create(It.Is<IEnumerable<int>>(l => VerifyList(l))));
}
private static bool VerifyList(IEnumerable<int> enumerable)
{
return enumerable.Contains(1) && enumerable.Contains(2) && enumerable.Contains(5);
}
private IEnumerable<int> CreateList()
{
return new[] { 3, 4, 5 };
}
public interface IRepository
{
IEnumerable<int> Get();
int Create(IEnumerable<int> id);
}
public class Service
{
public Service(IRepository repository)
{
this.repository = repository;
}
private IRepository repository;
public int Save(IEnumerable<int> addedIds, IEnumerable<int> removedIds)
{
var existingIds = repository.Get();
IEnumerable<int> ids = existingIds.Except(removedIds).Union(addedIds);
return repository.Create(ids);
}
You can do:
var another = new List<int> { 1 , 2, 3 };
repository.Verify(r => r.Create(It.Is<IEnumerable<int>>(l => l.SequenceEqual(another)));
Something quick and dirty -
public interface IBlah
{
void Sum(IEnumerable<int> baz);
}
class Blah : IBlah
{
public void Sum(IEnumerable<int> baz)
{
return;
}
}
public class Baz
{
private readonly IBlah blah;
public Baz(IBlah blah)
{
this.blah = blah;
}
public void Sum(IEnumerable<int> baz)
{
blah.Sum(baz);
}
}
And Test it like -
[Test]
public void foo()
{
var mock = new Mock<IBlah>();
var enumerable = Enumerable.Range(1, 10);
var baz = new Baz(mock.Object);
baz.Sum(enumerable.Where(x => x%2 == 0));
mock.Verify(p => p.Sum(It.Is<IEnumerable<int>>(z => z.All(x => x%2==0))));
}