I want to mock a unit of work interface with repositories inside for unit test purpose. So far I am able to do it like below.
namespace Liquid.Service.UnitTest
{
using Liquid.DataAccess.Interface;
using Liquid.Domain;
using Domain.Interface;
using Moq;
using System.Collections.Generic;
using System.Linq;
internal class Helper
{
internal Mock<IUnitOfWork> MockUnitOfWork(ICollection<Dummy> dummies = null,
ICollection<ProductType> productTypes = null)
{
dummies = dummies ?? new List<Dummy>();
productTypes = productTypes ?? new List<ProductType>();
var dummyRepositoryMock = MockDummyRepository(dummies);
var productTypeRepositoryMock = MockProductTypeRepository(productTypes);
var unitOfWorkMock = new Mock<IUnitOfWork>();
unitOfWorkMock.Setup(x => x.DummyRepository)
.Returns(dummyRepositoryMock.Object);
unitOfWorkMock.Setup(x => x.ProductTypeRepository)
.Returns(productTypeRepositoryMock.Object);
return unitOfWorkMock;
}
private Mock<IDummyRepository> MockDummyRepository(ICollection<Dummy> dummies)
{
var dummyRepositoryMock = new Mock<IDummyRepository>();
dummyRepositoryMock.Setup(x => x.FindById(It.IsAny<int>()))
.Returns((int arg1) => dummies.Where(x => x.Id == arg1).SingleOrDefault());
dummyRepositoryMock.Setup(x => x.Add(It.IsAny<Dummy>()))
.Callback((Dummy arg1) => dummies.Add(arg1));
return dummyRepositoryMock;
}
private Mock<IProductTypeRepository> MockProductTypeRepository(ICollection<ProductType> productTypes)
{
var productTypeRepositoryMock = new Mock<IProductTypeRepository>();
productTypeRepositoryMock.Setup(x => x.FindById(It.IsAny<int>()))
.Returns((int arg1) => productTypes.SingleOrDefault(x => x.Id == arg1));
productTypeRepositoryMock.Setup(x => x.Add(It.IsAny<ProductType>()))
.Callback((ProductType arg1) => productTypes.Add(arg1));
return productTypeRepositoryMock;
}
}
}
You see that I've created two method to mock DummyRepository and ProductTypeRepository but because it has same implementation, I think it is redundant for every repositories I have.
Below is the Repositories and IRepository code.
namespace Liquid.DataAccess.Interface
{
using Liquid.Domain;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public interface IDummyRepository : IRepository<Dummy>
{
}
public interface IProductTypeRepository : IRepository<ProductType>
{
}
public interface IRepository<TEntity> where TEntity : class
{
IList<TEntity> GetAll();
Task<List<TEntity>> GetAllAsync();
Task<List<TEntity>> GetAllAsync(CancellationToken cancellationToken);
IList<TEntity> PageAll(int skip, int take);
Task<List<TEntity>> PageAllAsync(int skip, int take);
Task<List<TEntity>> PageAllAsync(CancellationToken cancellationToken, int skip, int take);
TEntity FindById(object id);
Task<TEntity> FindByIdAsync(object id);
Task<TEntity> FindByIdAsync(CancellationToken cancellationToken, object id);
void Add(TEntity entity);
void Update(TEntity entity);
void Remove(TEntity entity);
}
}
How can I use a same method to mock every repositories implementation which inherits IRepository?
UPDATE :
The test is just a simple add and check like below.
[Test]
public void ProductTypeService_Add()
{
// GIVEN
var productTypeData = new ProductType()
{
Id = 1,
Description = "ProductType1"
};
// WHEN
var unitOfWorkMock = new Helper().MockUnitOfWork();
var productTypeService = new ProductTypeService(unitOfWorkMock.Object);
productTypeService.Add(productTypeData);
unitOfWorkMock.Verify(x => x.SaveChanges());
// THEN
Assert.That(productTypeService.FindById(1) != null);
Assert.That(productTypeService.FindById(2) == null);
// WHEN
var productTypeData2 = new ProductType()
{
Id = 2,
Description = "ProductType2"
};
productTypeService.Add(productTypeData2);
// THEN
Assert.That(productTypeService.FindById(2) != null);
}
IMHO you are testing the wrong thing; namely you are testing that an in-memory collection (a List<T>) can store data and the data can be found in the collection. This always yields true because that is the purpose of in-memory collections.
Instead of doing this you either need to create integration tests which will use the actual implementation of the underlying repository (such as Entity Framework) or just test the behavior of your service like this:
[Test]
public void ProductTypeService_WhenAddingNewItem_CallsSaveChanges()
{
var unitOfWork = new Mock<IUnitOfWork>();
// setup the properties of the mock here...
var service = new ProductTypeService(unitOfWork);
service.Add(new ProductType { Id = 2, Description = "some product" });
unitOfWork.AssertWasCalled(_ => _.SaveChanges());
}
This way, you test that your service calls SaveChanges() method; actually saving the data is the responsibility of the repository and as I said above, testing that a list can store data in memory is useless.
I think you have over complicated your question and thus your solution. You don't need interfaces for your various repositories like IDummyRepository and IProductRepository if you are not adding any value to it.
Your data classes
public class Dummy
{
public int Id { get; set; }
}
public class ProductType
{
public int Id { get; set; }
}
Your ProductTypeService (I can only assume this)
public class ProductTypeService
{
private readonly IUnitOfWork _unitOfWork;
public ProductTypeService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public void AddProductType(ProductType productType)
{
_unitOfWork.ProductTypes.Add(productType);
}
}
Your IUnitOfWork
public interface IUnitOfWork
{
IRepository<Dummy> Dummies { get; set; }
IRepository<ProductType> ProductTypes { get; set; }
}
Your IRepository remains unchanged so I won't copy paste it here!
Finally your unit test
[TestFixture]
public class Class1
{
private Mock<IUnitOfWork> _unitOfWorkMock;
private Mock<IRepository<Dummy>> _dummyRepositoryMock;
private Mock<IRepository<ProductType>> _productTypeRepositoryMock;
[SetUp]
public void Setup()
{
_unitOfWorkMock = new Mock<IUnitOfWork>();
_dummyRepositoryMock = CreateMock<Dummy>();
_productTypeRepositoryMock = CreateMock<ProductType>();
_unitOfWorkMock.Setup(u => u.Dummies).Returns(_dummyRepositoryMock.Object);
_unitOfWorkMock.Setup(u => u.ProductTypes).Returns(_productTypeRepositoryMock.Object);
}
[Test]
public void product_type_service_should_add_item_to_the_underlying_repository()
{
var productTypeService = new ProductTypeService(_unitOfWorkMock.Object);
var productType = new ProductType {Id = 10};
productTypeService.AddProductType(productType);
_productTypeRepositoryMock.Verify(r => r.Add(It.Is<ProductType>(p => p.Id == productType.Id)), Times.Once());
}
private Mock<IRepository<T>> CreateMock<T>() where T : class
{
var mock = new Mock<IRepository<T>>();
// do more common magic here
return mock;
}
}
Related
I am trying to write some tests for an existing service we have. It uses the DbContext (In our case, named DatabaseContext) and the constructor looks like this:
public GenericOrderProvider(DatabaseContext context, IOrderHandler<T> orderHandler)
{
_orderHandler = orderHandler;
_context = context;
_dbSet = context.Set<T>();
}
As you can see, it's generic and sets the _dbSet when it's initialized.
I have this very simple method:
public Attempt<IQueryable<T>> List(params string[] includes)
{
var x = _dbSet.ToList();
return Attempt<IQueryable<T>>.Succeed(_dbSet.OrderBy(m => m.Order));
}
And I wrote this test:
[TestFixture]
public class ListShould
{
[Test]
public void ReturnList()
{
// Assemble
var services = GenericOrderProviderContext.GivenServices();
var provider = services.WhenCreateOrderProvider();
services.DatabaseContext.Set<Attribute>().ReturnsForAnyArgs(new List<Attribute>().ToDbSet());
//services.DatabaseContext.Attributes = new List<Attribute>().ToDbSet();
// Act
var result = provider.List();
// Assert
result.Failure.Should().BeFalse();
result.Result.Count().Should().Be(0);
}
}
When I run that test, I get the error:
NSubstitute.Exceptions.CouldNotSetReturnDueToNoLastCallException : Could not find a call to return from.
The trace specifically targets the line services.DatabaseContext.Set<Attribute>().ReturnsForAnyArgs(new List<Attribute>().ToDbSet()); but I have no idea how to fix it.
As far as I can tell, I am mapping to the right method.
For completeness, here is my test Contexts:
public class GenericOrderProviderContext: DatabaseContextContext<GenericOrderProviderContext>
{
public static GenericOrderProviderContext GivenServices() => new GenericOrderProviderContext();
public IGenericOrderProvider<Attribute> WhenCreateOrderProvider() =>
new GenericOrderProvider<Attribute>(DatabaseContext,
new OrderHandler<Attribute>(DatabaseContext));
public bool IsSequential(List<Attribute> models)
{
return !models.OrderBy(m => m.Order).Select(m => m.Order).Select((i, j) => i - j).Distinct().Skip(1).Any();
}
}
public class DatabaseContextContext<T> where T: DatabaseContextContext<T>
{
public DatabaseContext DatabaseContext;
protected DatabaseContextContext()
{
DatabaseContext = Substitute.For<DatabaseContext>();
}
}
Does anyone know what I can do to resolve this issue?
I am new to Moq framework. I have a viewmodel with injected IEntityRepository
public class MainViewModel
{
private readonly IEntityRepository _entityRepository;
public MainViewModel(IEntityRepository entityRepository)
{
_entityRepository = entityRepository;
Entities = new ObservableCollection<EntityWrapper>();
}
public ObservableCollection<EntityWrapper> Entities { get; set; }
public void Load()
{
var entities = _entityRepository.GetAll();
Entities.Clear();
foreach (var entity in entities)
{
Entities.Add(new EntityWrapper(entity));
}
}
public void AddEntity(string name, int x, int y)
{
var entity = new Entity()
{
Name = name,
X = x,
Y = y
};
_entityRepository.AddEntity(entity);
_entityRepository.Save();
}
}
and EntityRepository is like this:
public class EntityRepository : IEntityRepository
{
private Context _context;
public EntityRepository(Context context)
{
_context = context;
}
public Entity Get(long id)
{
return _context.Entities.Find(id);
}
public IEnumerable<Entity> GetAll()
{
return _context.Entities.ToList();
}
public void AddEntity(Entity entity)
{
_context.Entities.Add(entity);
}
public void Save()
{
_context.SaveChanges();
}
}
Now, I want to test Load and AddEntity methods of MainViewModel
this is my test class:
[TestClass]
public class MainViewModelTests
{
private Mock<IEntityRepository> _mockRepo;
private MainViewModel _mainViewModel;
public MainViewModelTests()
{
_mockRepo = new Mock<IEntityRepository>();
_mainViewModel = new MainViewModel(_mockRepo.Object);
}
[TestMethod]
public void AddEntityTest()
{
var entity = new Entity()
{
Name = "Student",
X = 10,
Y = 20
};
_mainViewModel.AddEntity("Student", 10, 20);
_mockRepo.Setup(m => m.AddEntity(entity));
_mockRepo.Setup(m => m.Save());
var entities = _mainViewModel.Entities;
Assert.AreEqual(1, entities.Count);
}
[TestMethod]
public void LoadTest()
{
// How to add fake data???
_mockRepo.Setup(r => r.GetAll());
_mainViewModel.Load();
var entities = _mainViewModel.Entities;
Assert.AreEqual(1, entities.Count);
}
}
In AddEntityTest() I don't know why the property Entities will be empty and in LoadTest how to populate fake data so that I can load it.
To get a test data in LoadTest method you can use Moq Returns method
_mockRepo.Setup(r => r.GetAll()).Returns(new List<Entity> { new Entity() });
It works, because List<T> implements IEnumerable<T>.
As for the AddEntityTest, there are a couple of issues here. You setup the mock
_mockRepo.Setup(m => m.AddEntity(entity));
_mockRepo.Setup(m => m.Save());
after _mainViewModel.AddEntity("Student", 10, 20); call. It should come before, Arrange step is always before Act step, according to AAA pattern
You also don't update Entities collection after adding an entity, so the Entities.Count remains the same. I suggest you to setup a IEntityRepository.GetAll() mock as well for this test and update an Entities collection in MainViewModel. Or rewrite the logic of your AddEntityTest, if collection update performed through view
I am trying to test a bit of code I have:
public async Task<Sortation> SaveAsync(Sortation sortation)
{
if (sortation.Id == 0)
{
var sortations = await ListAsync(sortation.CategoryId);
sortation.Order = sortations.Count;
_sortationService.Create(sortation);
}
else
{
_sortationService.Update(sortation);
}
await _sortationService.SaveChangesAsync();
return sortation;
}
The ListAsync method is causing me an issue.
I set up my test like this:
[Test]
public async Task ShouldHaveOrderOfZero()
{
// Assemble
const string categoryId = "cameras";
var services = SortationContext.GivenServices();
var sortationProvider = services.WhenGetSortationProvider();
var sortations = new List<Sortation>();
var sortation = new Sortation { CategoryId = categoryId };
services.MockSortationService.Setup(x => x.List()).Returns(sortations.AsQueryable);
// Act
await sortationProvider.SaveAsync(sortation);
// Assert
sortation.Order.Should().Be(0);
}
And when I run this, I get this error:
Message: System.InvalidOperationException : The source IQueryable doesn't implement IDbAsyncEnumerable. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations.
According to this: Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations I need to add EF to my UnitTest project, which I did.
But the error still persists.
The ListAsync method looks like this:
public async Task<List<Sortation>> ListAsync(string categoryId, params string[] includes) =>
await _sortationService.List(includes).Where(m => m.CategoryId.Equals(categoryId)).ToListAsync();
Does anyone know how I can stop this error from happening?
In my case the exception was caused by using the wrong ToListAsync extension.
It came from:
using System.Data.Entity;
instead of
using Microsoft.EntityFrameworkCore;
Changing the namespace fixed the error.
Don't know if question is still actual, but still. I agree with Mark's comment, however here is an example, that works for me. I added some reasonable stub implementation for mentioned class, because there are not enouch details in question. I can be wrong in my assumptions:
[Test]
public async Task ShouldHaveOrderOfZero()
{
// Assemble
const string categoryId = "cameras";
var services = SortationContext.GivenServices();
var sortationProvider = services.WhenGetSortationProvider();
var sortations = new List<Sortation>();
var sortation = new Sortation { CategoryId = categoryId };
// the key moq configuration here
services.MockSortationService.Setup(x => x.ListAsync(It.IsAny<string>())).Returns(Task.FromResult(sortations));
// Act
await sortationProvider.SaveAsync(sortation);
// Assert
sortation.Order.Should().Be(0);
}
public class SortationProvider
{
private SortationService _sortationService;
public SortationProvider()
{
_sortationService = new SortationService();
}
public async Task<Sortation> SaveAsync(Sortation sortation)
{
if (sortation.Id == 0)
{
var sortations = await ListAsync(sortation.CategoryId);
sortation.Order = sortations.Count;
_sortationService.Create(sortation);
}
else
{
_sortationService.Update(sortation);
}
await _sortationService.SaveChangesAsync();
return sortation;
}
// should be virtual
public virtual async Task<List<Sortation>> ListAsync(string categoryId, params string[] includes) =>
await _sortationService.List(includes).Where(m => m.CategoryId.Equals(categoryId)).ToListAsync();
}
public class SortationContext
{
public static Services GivenServices()
{
return new Services();
}
}
public class Services
{
public Services()
{
MockSortationService = new Mock<SortationProvider>();
}
public SortationProvider WhenGetSortationProvider()
{
return MockSortationService.Object;
}
public Mock<SortationProvider> MockSortationService { get; set; }
}
internal class SortationService
{
public void Create(Sortation sortation)
{
}
public void Update(Sortation sortation)
{
}
public Task SaveChangesAsync()
{
return Task.CompletedTask;
}
public DbSet<Sortation> List(string[] includes)
{
throw new NotImplementedException();
}
}
public class Sortation
{
public string CategoryId { get; set; }
public int Id { get; set; }
public int Order { get; set; }
}
The main change is in line that contains Setup method. I made ListAsync method virtual also. The main assumption is that List(string[] includes) method returns DbSet<Sortation>. Hope it helps.
I get the following error:
test.Services.JobService' does not contain a constructor that takes
0 arguments.
this is the code:
JobService.cs:
namespace TesteUltrafan.Services
{
public class JobService
{
private readonly IRepository _repository;
public JobService(IRepository repository)
{
_repository = repository;
}
public Job CreateJobBanker()
{
var banker = new Job();
string id = Guid.NewGuid().ToString("N");
Console.WriteLine("Novo job banker id: {0}", id);
banker.Id = id;
banker.Type = JobType.Banker;
banker.CreatedAt = DateTime.Now;
Console.WriteLine("Salvando job banker id: {0}", id);
Job jobBanker = _repository.SaveJob(banker);
return jobBanker;
}
}
}
the program.cs:
public class Program
{
public static void Main()
{
var jobService = new JobService(); <---- Here is the error.
Console.WriteLine("Creating job banker, creation:");
Job jobBanker = jobService.CreateJobBanker();
Console.WriteLine("Job banker: {0}", jobBanker);
}
}
Job.cs:
public class Job
{
public string Id { get; set; }
public DateTime CreatedAt { get; set; }
public JobType Type { get; set; }
}
JobType.cs:
public enum JobType
{
Actor = 1,
Agricultural = 2,
Banker = 3,
EngineerCivil = 4,
Another = 5,
}
You either need to create a parameterless constructor in your JobService class (which I would not do because then your class will not work correctly - there will be no reference to any repository) or preferably pass a Repository instance as a parameter when constructing this instance.
So the code should preferably look like this:
public class Program
{
public static void Main()
{
var jobService = new JobService(new Repository());
Console.WriteLine("Creating job banker, creation:");
Job jobBanker = jobService.CreateJobBanker();
Console.WriteLine("Job banker: {0}", jobBanker);
}
}
Where Repository should be a class implementing IRepository interface. Without passing this instance your CreateJobBanker will not work.
What would be though recommended is to use some IoC Container, because your code follows the Inversion of Control principle (probably you are not even aware of this).
Use
var jobService = new JobService(new Repository());
because otherwise your JobService with not have an IRepository instance and will throw a NullReferenceException when you try to use your repository inside JobService.
In your code, you are initialising JobService without giving it a IRepository argument, to get your code to compile you need to define a constructor in JobService that does not have an IRepository argument if you want to do that:
public class JobService
{
private readonly IRepository _repository;
// New Constructor will make _repository null
public JobService()
{
}
public JobService(IRepository repository)
{
_repository = repository;
}
public Job CreateJobBanker()
{
var banker = new Job();
string id = Guid.NewGuid().ToString("N");
Console.WriteLine("Novo job banker id: {0}", id);
banker.Id = id;
banker.Type = JobType.Banker;
banker.CreatedAt = DateTime.Now;
Console.WriteLine("Salvando job banker id: {0}", id);
// NullReferenceException if you define a parameterless constructor
Job jobBanker = _repository.SaveJob(banker);
return jobBanker;
}
}
Now you can construct it in two ways:
var jobService = new JobService();
or
var jobService = new JobService(new Repository());
IRepository implementation:
public class Repository: IRepository
{
private MyDbEntities context = new MyDbEntities();
public Job SaveJob(Job job)
{
// assuming Entity Framework
var id = job.Id;
if (context.Jobs.Any(e => e.Id == id))
{
context.Jobs.Attach(job);
context.ObjectStateManager.ChangeObjectState(jobs, EntityState.Modified);
}
else
{
context.Jobs.AddObject(myEntity);
}
context.SaveChanges();
return job;
}
}
I have the following Repository Pattern. Requirement is to “Find All accounts whose owner’s name is Lijo”. So, I need to write a FindAll function. How to write this function?
Constraints are:
1) The client “BankAccountService” should not use classes from 'DBML_Project'.
2) We should NOT use GetAll method to retireve complete list of accounts and then do a filter.
Note: I confronted this problem while working on the question Polymorphism: Is ORM entity a Domain Entity or Data Entity?
CODE
namespace ApplicationService_Bank
{
public class BankAccountService
{
RepositoryLayer.ILijosBankRepository accountRepository = new RepositoryLayer.LijosSimpleBankRepository();
public void FreezeAllAccountsForUser(string userName)
{
//Should not use assembly 'DBML_Project'.
IEnumerable<DomainEntitiesForBank.IBankAccount> accountsForUserWithNameLIJO = null;
//accountsForUserWithNameLIJO = accountRepository.FindAll(p => p.BankUser.Name == "Lijo");
}
}
}
namespace RepositoryLayer
{
public interface ILijosBankRepository
{
List<DomainEntitiesForBank.IBankAccount> GetAll();
IEnumerable<DBML_Project.BankAccount> FindAll(System.Func<DBML_Project.BankAccount, bool> predicate);
void SubmitChanges();
}
public class LijosSimpleBankRepository : ILijosBankRepository
{
private IBankAccountFactory bankFactory = new MySimpleBankAccountFactory();
public System.Data.Linq.DataContext Context
{
get;
set;
}
public virtual List<DomainEntitiesForBank.IBankAccount> GetAll()
{
List<DBML_Project.BankAccount> allItems = Context.GetTable<DBML_Project.BankAccount>().ToList();
List<DomainEntitiesForBank.IBankAccount> bankAccounts = new List<DomainEntitiesForBank.IBankAccount>();
foreach (DBML_Project.BankAccount acc in allItems)
{
DomainEntitiesForBank.IBankAccount theAccount = bankFactory.CreateAccount(acc.AccountType, acc.BankAccountID, acc.Status, acc.OpenedDate, acc.AccountOwnerID);
bankAccounts.Add(theAccount);
}
return bankAccounts;
}
public IEnumerable<DBML_Project.BankAccount> FindAll(System.Func<DBML_Project.BankAccount, bool> predicate)
{
//Where
var results = Context.GetTable<DBML_Project.BankAccount>().Where(predicate);
return results;
}
public virtual void SubmitChanges()
{
Context.SubmitChanges();
}
}
}
READING:
Returning IEnumerable<T> vs. IQueryable<T>
how to design Repository pattern to be easy switch to another ORM later?
A simple approach is to just build the query by hand:
public class SearchCriteria
{
public string Name { get; set; }
// ...more
}
public IEnumerable<Entity> FindAll(SearchCriteria criteria)
{
IQueryable<Entity> entities = _datasource.Entities; // replace with your L2S equivalent
if (criteria.Name != null)
entities = entities.Where(e => e.Name == criteria.Name);
// ...more
return entities;
}
If you don't want to return the generated objects directly, map to something else before you return:
return Map(entities); // IEnumerable<CustomObject> Map(IEnumerable<Entity> entities)