C# mocking generic repository using Moq - c#

I have implemented generic repository in my project. Now I am writing test cases for my consumer. I am trying to mock database function through Moq but I am getting values from database rather than the one I faked through Moq. Below I am sharing my implementation. Hoping someone will help me in pointing out the mistake I made.
My interface:
public interface IEventsRepository<T> : IRepository<T> {
T GetEventsByEventId(int eventId); }
My class:
public class EventsTableRepository : EFDBRepository<EventsModel>, IEventsRepository<EventsModel> {
public EventsModel GetEventsByEventId(int eventId)
{
return _dbSet.Where(x => x.EventID == eventId).FirstOrDefault();
}
}
My Consumer:
public static Response<string> EventsAccept(EventsAlertsRequest logMsgId)
{
IEventsRepository<EventsModel> eventsRepo = (IEventsRepository<EventsModel>)RepositoryLocator.GetRepositoryObject(STMEnums.RepositoryName.EventsTableRepository.ToString());
EventsModel eventmodel = new EventsModel();
eventmodel = eventsRepo.GetEventsByEventId(eachlogMsgId);
return EventStatusChangeResponse;
}
Test Method:
public void EventsAcceptSuccessTest()
{
EventsModel eventmodel = new EventsModel();
eventmodel.Message = "TEST";
Mock<IEventsRepository<EventsModel>> obj = new Mock<IEventsRepository<EventsModel>>();
obj.Setup(m => m.GetEventsByEventId(Moq.It.IsAny<int>())).Returns(eventmodel);
EventStatusChangeResponse = Diagnostics_.EventsAccept(logMsgId);
Assert.AreEqual(eventmodel.Status, EventStatus.ACCEPTED);
}

No where in the provided example is the mock being injected into the subject under test. Also it looks like the subject method under test is using static Service Locator anti-pattern to get the desired model. Making an assumption here as the rest of the class is not shown in relation to that variable.
The locator would need to have been an injected abstraction to allow an opportunity to mock its expected behavior
public class Consumer {
private IRepositoryLocator RepositoryLocator;
public Consumer(IRepositoryLocator RepositoryLocator) {
this.RepositoryLocator = RepositoryLocator;
}
public Response<string> EventsAccept(EventsAlertsRequest logMsgId) {
IEventsRepository<EventsModel> eventsRepo = (IEventsRepository<EventsModel>)RepositoryLocator.GetRepositoryObject(STMEnums.RepositoryName.EventsTableRepository.ToString());
EventsModel eventmodel = new EventsModel();
eventmodel = eventsRepo.GetEventsByEventId(eachlogMsgId);
return EventStatusChangeResponse;
}
}
This would then mean that the locator would also have to be mocked properly for the test to be exercised to completion.
public void EventsAcceptSuccessTest() {
//Arrange
var eventmodel = new EventsModel() {
Message = "TEST"
};
var repositoryMock = new Mock<IEventsRepository<EventsModel>>();
repositoryMock
.Setup(_ => _.GetEventsByEventId(It.IsAny<int>()))
.Callback((int id) => {
eventmodel.EventID = id;
eventmodel.Status = EventStatus.ACCEPTED;
})
.Returns(eventmodel);
var locatorMock = new Mock<IRepositoryLocator>();
locatorMock.Setup(_ => _.GetRepositoryObject(It.IsAny<string>())).Returns(repositoryMock.Object);
var subject = new Consumer(locatorMock.Object);
//Act
var response = subject.EventsAccept(logMsgId);
//Assert
Assert.AreEqual(eventmodel.Status, EventStatus.ACCEPTED);
}

Related

How to mock DbSet using xUnit and NSubstitute?

I started using xUnit and NSubstitute for my unit tests. I want to mock the following method.
public async Task<DecorationModel> GetDecorationWithId(string userId, string decorationId)
{
var decoration = await _db.Decorations
.Include(d => d.BgImage)
.FirstOrDefaultAsync(d => d.Id == decorationId);
if (decoration == null || decoration.OwnerId != userId)
return null;
return new DecorationModel
{
Id = decoration.Id,
Name = decoration.Name,
// Other stuff
};
}
I attempted it but couldn't get it to work. My current test class is as follows;
public class DecorationServiceTests
{
private readonly DecorationService _subject;
private readonly IAppDbContext _db = Substitute.For<IAppDbContext>();
private readonly DbSet<Decoration> _decorationDbSet = Substitute.For<DbSet<Decoration>, IQueryable<Decoration>>();
public DecorationServiceTests()
{
_subject = new DecorationService(_db);
}
[Fact]
public async Task GetDecorationWithId_ShouldReturnDecoration_WhenExists()
{
// Arrange
var userId = new Guid().ToString();
var decorationId = new Guid().ToString();
var decorations = new List<Decoration>()
{
new Decoration()
{
Id = decorationId,
Name = "",
OwnerId = userId,
}
};
_db.Decorations.Returns(_decorationDbSet);
_decorationDbSet.FirstOrDefaultAsync(t => t.Id == decorationId).Returns(decorations.FirstOrDefault());
// Act
var result = await _subject.GetDecorationWithId(userId, decorationId);
// Assert
Assert.Equal(result.Id, decorations[0].Id);
}
}
However, I get the following error:
"The provider for the source 'IQueryable' doesn't implement 'IAsyncQueryProvider'. Only providers that implement 'IAsyncQueryProvider' can be used for Entity Framework asynchronous operations."
I searched on the web but couldn't find a good reference. How can I solve this?
I think you'll be going through a whole lot of pain and suffering if you are trying to mock DbSet. That comes straight from the docs of EFCore: https://learn.microsoft.com/en-us/ef/core/testing/#unit-testing
Instead, you should be trying to use a real db or in-memory one.
See the testing sample here: https://learn.microsoft.com/en-us/ef/core/testing/testing-sample

How convert from Moq to NSubstitute that code?

Moq:
var someService = new Mock<ISomeService>();
var data = new ...;
someService.Setup(x => x.UpdateAsync(It.IsAny<Action<OneClass, TwoClass>>()))
.Callback<Action<OneClass, TwoClass>>((func) =>
{
func(data);
})
.Returns(Task.CompletedTask);
UpdateAsync have action (first parameter).
I want to execute action.
I tried
someService
.UpdateAsync(Arg.Do<Action<OneClass, TwoClass>>(x => x(data)))
.Returns(Task.CompletedTask);
but it didn`t work.
How is this done using NSubstitute?
You have an action that takes two arguments yet try to invoke it using only one
The following example test verifies the expected behavior and that the mocking framework does in fact behave as expected.
[TestClass]
public class MyTestClass {
[TestMethod]
public async Task Should_Invoke_Callback() {
//Arrange
var someService = Substitute.For<ISomeService>();
OneClass one = new OneClass();
TwoClass two = new TwoClass();
someService
.UpdateAsync(Arg.Do<Action<OneClass, TwoClass>>(action => action(one, two)))
.Returns(Task.CompletedTask);
bool invoked = false;
Action<OneClass, TwoClass> callback = (a, b) => {
invoked = a != null && b != null;
};
//Act
await someService.UpdateAsync(callback);
//Assert - using FluentAssertions
invoked.Should().BeTrue();
}
}
public class TwoClass {
}
public class OneClass {
}
public interface ISomeService {
Task UpdateAsync(Action<OneClass, TwoClass> action);
}
Reference Actions with argument matchers

How to use MOQ in crud operations

I am having the a typical CRUD operation interface (repository) and i was wondering how would someone test it using MOQ.
Model
public class Model
{
public int Id{get;set;}
}
Interface
public interface ICrud
{
Task<IEnumerable<Model>> GetAllAsync();
Task AddAsync(Model model);
}
Service
public class Service
{
public ICrud operations;
Service(ICrud crud){ this.operations=crud;}
public Task<IEnumerable<Model>> GetAllAsync()=>this.operations.GetAllAsync();
public Task AddAsync(Model model)=> this.operations.AddAsync(model);
}
Unit Test
public class Test
{
public IEnumerable Seed(){
yield return new Model {id=3};
yield return new Model {id =4};
}
[Testcase(3)]
public async Task CanAdd(int id)
{
var mock=new Mock<ICrud>();
var newModel=new Model{ Id=id};
mock.Setup(x=>x.GetAsync()).ReturnsAsync(Seed);
mock.Setup(x=>x.AddAsync(newModel));
//how can i test adding the new model
var service=new Service(mock.Object);
var initialList=await service.GetAllAsync();
//adding
await service.AddAsync(newModel);
var finalList=await service.GetAllAsync();
}
}
My question is , how can i test the following scenario:
-i check the initial collection
-i call `AddAsync`
-i check to see that the new collection contains the added element.
How can this be achieved with Moq in a unit test?
Or you can do it without mocking frameworks.
public class InMemoryCrud : ICrud
{
public List<Model> Models { get; set; } = new List<Model>();
public Task<IEnumerable<Model>> GetAllAsync() => return Task.FromResult(Models);
public Task AddAsync(Model model)
{
Models.Add(model);
return Task.CompletedTask;
}
}
public async Task Add_Model()
{
var fakeCrud = new InMemoryCrud();
var service = new Service(fakeCrud);
var newModel = new Model { Id = 3 };
await service.AddAsync(newModel);
var actualModels = await fakeCrud.GetAllAsync();
var expected = new[]
{
new Model { Id = 3 }
}
actualModels.Should().BeEquivalentTo(expected); // Pass
}
With InMemoryCrud implementation you can test that correct values ahs been "saved" via crud operations.
With mocking frameworks you will test that correct methods has been called. For example if in Service class I change some properties of the given instance of the Model - tests still pass, but wrong data will be saved to the database in real application.
In this scenario, pass case is that the subject service under test correctly invokes the dependency operation with the given model.
The test should thus reflect that when being exercised.
Using MOQ that would look like
public async Task Service_Should_AddAsync() {
//Arrange
int id = 1;
var mock = new Mock<ICrud>();
var newModel = new Model { Id = id };
mock.Setup(x => x.AddAsync(It.IsAny<Model>())).Returns(Task.CompletedTask);
var service = new Service(mock.Object);
//Act
await service.AddAsync(newModel);
//Assert
//verify that the mock was invoked with the given model.
mock.Verify(x => x.AddAsync(newModel));
}

Need help calling a Repository from a Controller in Unit Testing

I am needing to set up a Unit Test for our project. In our Controllers we are using a Unit of Work which holds all the repositories and calling the repository in our IHttpActionResult to get the data.
So far I have set up a Mock of the Interfaces and this is calling the correct IHttpActionResult in the Controller but there is no data coming back.
[TestMethod]
public void TestMethod1()
{
var unitOfWork = new Mock<IUnitOfWork>();
var repo = new Mock<IAuditReleaseRepository>();
unitOfWork.Setup(e => e.AuditReleaseRepository).Returns(repo.Object);
var auditReleaseController = new AuditReleaseController(unitOfWork.Object);
var result = auditReleaseController.Get() as ViewResult;
var model = result.ViewData.Model as IQueryable<AuditReleas>;
Assert.AreEqual(12, model.Count());
}
public class AuditReleaseController : BaseController
{
private IAuditReleaseRepository _auditReleaseRepository;
private IUnitOfWork _unitOfWork;
public AuditReleaseController(IUnitOfWork unitOfWork)
{
this._unitOfWork = unitOfWork;
this._auditReleaseRepository = unitOfWork.AuditReleaseRepository;
}
[HttpGet, Route("audit-releases")]
public IHttpActionResult Get()
{
var query = this._auditReleaseRepository.GetAll();
return Ok(query);
}
}
public class AuditReleaseRepository : RepositoryBase<AuditReleas>, IAuditReleaseRepository
{
private readonly RetailAssignmentEntities _entities;
public AuditReleaseRepository(RetailAssignmentEntities entities) : base(entities)
{
this._entities = entities;
}
IEnumerable<AuditReleaseDto> IDtoRepository<AuditReleaseDto>.GetAll()
{
return base.GetAll().Where(x=>x.IsReleaseEnabled).Select(AuditReleaseMapping.All).OrderByDescending(x => x.Id);
}
}
This is the Mapping that is taking place to get the data in the GetAll method:
public class AuditReleaseMapping
{
public static Expression<Func<AuditReleas, AuditReleaseDto>> All = (auditRelease) => new AuditReleaseDto()
{
EndDate = auditRelease.AuditReleaseEndDate,
Id = auditRelease.AuditReleaseId,
Name = auditRelease.AuditReleaseName,
StartDate = auditRelease.AuditReleaseStartDate,
AuditPeriodId = auditRelease.AuditPeriod.AuditPeriodId,
AuditYearId = auditRelease.AuditPeriod.AuditYear.AuditYearId,
AuditEndDate = auditRelease.AuditPeriod.AuditEndDate,
AuditStartDate = auditRelease.AuditPeriod.AuditStartDate
};
}
What would be ideal is to call the Controller, which would call the repository, which would then call the Mapping but so far it's not even calling the Repository to get the data. I need help getting that functionality set up.
It looks like you need to Setup the behavior for your Mock repo.GetAll(). You will need to create a list of AuditReleaseDto's for your Mocked repo to return. Call it TestAuditReleaseDtos. You can create this TestData in the beginning of your TestMethod or in the TesstClass initialization. Then use it in a line right after creating your Mock:
var repo = new Mock<IAuditReleaseRepository>();
repo.Setup(r => r.GetAll()).Returns(TestAuditReleaseDtos);
unitOfWork.Setup(e => e.AuditReleaseRepository).Returns(repo.Object);

Supply my mock model with mock context

In a few words. Wpf app, ef used. I need to test model behavior using mock and unity. Unity and mock seem to me to be clear.
The question is following:
Model doesn't get the context through it constructor. It uses the context while execute the methods like this:
public Toys[] Get()
{
using (Context context = new Context())
{
return context.Toys.ToArray();
}
}
This is how I try to test:
[TestClass]
public class TestToyModel
{
[TestMethod]
public void TestToyCreate()
{
List<Toy> toys = new List<Toy>();
toys.Add(new Toy{ Id = "1234", Name = "Toy1" });
DbSet<Toy> dbToys = GetQueryableMockDbSet(toys);
Mock<ToyModel> model = new Mock<ToyModel>();
Mock<Context> context = new Mock<Context>();
context.Setup(x => x.Toys).Returns(dbToys);
//it' s all for now
}
private static 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));
return dbSet.Object;
}
}
How can I supply my mock model with mock context ?
The context is being created manually so the class is tightly coupled to context which makes it difficult to unit test in isolation.
context is a dependency. abstract it out so that it can be mocked and injected into the subject under test.
public interface IContext : IDisposable {
public DbSet<Toy> Toys { get; }
//...other properties and methods
}
public class Context : DbContext, IContext {
public Context() { ... }
public DbSet<Toy> Toys { get; set; }
//...other properties and methods
}
Assuming system under test
public class ToyModel {
private readonly IContext context;
public MyClass(IContext context) {
this.context = context;
}
public Toys[] Get() {
return context.Toys.ToArray();
}
public void Create(Toy toy) {
context.Toys.Add(toy);
context.SaveChanges();
}
}
The class is no longer responsible for creating the dependency. That responsibility is now passed/delegated out to another class. Also note that your classes should depend on abstractions and not on concretions. This allows for more flexibility when swapping implementations. Like mocking for unit tests.
Now the context can be mocked and injected into the dependent class. Here is a simple example based on what you have done so far.
[TestClass]
public class TestToyModel {
[TestMethod]
public void TestToyCreate() {
//Arrange
var toys = new List<Toy>();
toys.Add(new Toy { Id = "1234", Name = "Toy1" });
var dbToys = GetQueryableMockDbSet(toys); //DbSet<Toy>
var contextMock = new Mock<IContext>();
contextMock.Setup(x => x.Toys).Returns(dbToys);
var sut = new ToyModel(contextMock.Object);
//Act
sut.Create(new Toy { Id = "5678", Name = "Toy2" });
//Assert
var expected = 2;
var actual = toys.Count;
Assert.AreEqual(expected, actual);
}
//...other code removed for brevity
}
If the ToyModel is the system under test, there is no need to mock it. Create an instance and pass the mocked dependencies to satisfy the test.

Categories