My repository is derived from a Class and an interface.
I want to mock the inherited method from the class, see the code here:
public interface IPersonRepository: ICommonRepository<PersonEntity>
{
PersonEntity GetPersonDetailById(string Id);
}
public class PersonRepository: CommonRepository<PersonEntity>, IPersonRepository
{
public PersonRepository(DatabaseContext context, ILogger logger) : base(context, logger){}
public PersonEntity GetPersonDetailById(string Id)
{
DataTable records = GetAllById(Id); // Who to Mock this method only
}
}
And Here is my unit test code
public Mock<ILogger> mockLogger = new Mock<ILogger>();
public DbContextOptions<DatabaseContext> options =
new DbContextOptionsBuilder<DatabaseContext>()
.UseInMemoryDatabase(databaseName: "DB_InMemory")
.Options;
public Mock<PersonRepository> personRepo =
new Mock<PersonRepository>(context, mockLogger.Object);
personRepo.CallBase = true;
personRepo.Setup(m => m.GetAllById(It.IsAny<string>>()))
.Returns(new System.Data.DataTable());
// Above line gives an error, see the error at the end
var response = personRepo.Object.GetPersonDetailById("1234");
Assert.NotNull(response);
Here is the error:
Non-overridable members (here: CommonRepository.GetAllById) may not be used in setup / verification expressions
Any suggestion or way to mock it?
Related
I have the following setup:
A calendar controller that calls a calendar service that calls a calendar client wrapper that calls the client. Controller -> Service -> ClientWrapper -> Client.
I am making an integration test that mocks the lowest tier (the client) and calls the controller to see if the client was called correctly.
My CalendarControllerBuilder:
internal class CalendarControllerBuilder
{
public CalendarControllerBuilder()
{
CalendarClientMock = new Mock<ICalendarServiceClient>(MockBehavior.Strict);
}
public Mock<ICalendarServiceClient> CalendarClientMock { get; set; }
public CalendarControllerBuilder With(Mock<ICalendarServiceClient> calendarClientWrapperMock)
{
CalendarClientMock = calendarClientWrapperMock;
return this;
}
public CalendarController Create()
{
var calendarClientWrapperMock = new CalendarClientWrapper(CalendarClientMock.Object);
var calenderService = new CalendarService(calendarClientWrapperMock);
return new CalendarController(calenderService);
}
}
Test setup with customization registration:
internal class CalenderControllerCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Register<CalendarController>(() =>
{
// ----- ICalendarServiceClient mock setups -----
var calendarServiceClientMock = new Mock<ICalendarServiceClient>(MockBehavior.Strict);
calendarServiceClientMock.Setup(m => m.GetEvents(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(fixture.Create<EventList>()).Verifiable();
return new CalendarControllerBuilder()
.With(calendarServiceClientMock)
.Create();
});
}
}
My automoq data attribute (using AutoFixture.Xunit2):
public class Attributes
{
public class AutoMoqDataAttribute<T> : AutoDataAttribute where T : ICustomization, new()
{
public AutoMoqDataAttribute()
: base(() => new Fixture()
.Customize(
new CompositeCustomization(
new AutoMoqCustomization(),
new T())))
{
}
}
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(() => new Fixture()
.Customize(
new AutoMoqCustomization()))
{
}
}
}
My test that works fine and uses the customization registration:
[Theory]
[AutoMoqData<CalenderControllerCustomization>]
public async Task Test_GetAllEvents_ClientIsCalledCorrectlyAndReturnsCorrectData(
IFixture fixture,
[Frozen] Mock<ICalendarServiceClient> calendarServiceClientMock,
CalendarController sut)
{
// Arrange
var startDate = fixture.Create<DateTimeOffset>();
var endDate = fixture.Create<DateTimeOffset>();
// Act
var eventList = await sut.GetAllEvents(startDate, endDate);
// Assert
eventList.Events.Count.Should().Be(3); // fixture always create 3 of lists here
calendarServiceClientMock.Verify();
}
THE PROBLEM:
Now I want to override the setup with my own data returned.
[Theory]
[AutoMoqData<CalenderControllerCustomization>]
public async Task Test_GetAllEvents_ClientIsCalledCorrectlyAndReturnsCorrectData_Overridden(
IFixture fixture,
[Frozen] Mock<ICalendarServiceClient> calendarServiceClientMock,
CalendarController sut)
{
// Arrange
var startDate = fixture.Create<DateTimeOffset>();
var endDate = fixture.Create<DateTimeOffset>();
var result = fixture.Build<EventList>()
.With(x => x.Events, fixture.CreateMany<Event>(5).ToList())
.Create();
// override client mock setup:
calendarServiceClientMock.Setup(m => m.GetEvents(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(fixture.Build<EventList>()
.With(x => x.Events, fixture.CreateMany<Event>(5).ToList())
.Create()).Verifiable();
// Act
var eventList = await sut.GetAllEvents(startDate, endDate);
// Assert
eventList.Events.Count.Should().Be(5); // FAILS - IT GETS 3 AND NOT 5
calendarServiceClientMock.Verify(); // THIS FAILS TOO IF I SET 3 IN ABOVE
}
I have tried with and without the Frozen attribute.
What am I missing here? I don't want to call my calendarcontroller builder as the point is to avoid boilerplate. Do I need a registration of the client or something else I'm missing
(maybe related to Override Autofixture customization setup but using moq and not n-subtitute. Could not get this to work even with correct order of parameters)
Thanks for reading!
With the current way you customize the fixture I don't think you can. By creating a custom builder and instantiating the mock by hand you've basically painted yourself in a corner.
To get AutoFixture to control the instances you need in the test, you must allow it to generate them. Here's a possible solution.
The root of your SUT is the controller. Let's say it receives as a parameter an ICalendarService that's always the concrete implementation CalendarService.
To tell AutoFixture that the implementation is always a concrete type you can relay the resolved type to the concrete implementation.
fixture.Customizations.Add(new TypeRelay(typeof(ICalendarService), typeof(CalendarService)));
Next the service takes as a constructor parameter an abstraction that's ICalendarClient which is resolved as the wrapper but only for the service. This means you have to identify the constructor parameter and relay the request to the wrapper type.
fixture.Customizations.Add(new FilteringSpecimenBuilder(
new FixedRequestRelay(typeof(CalendarClientWrapper)),
new YourConstructorParameterSpecification()));
The YourConstructorParameterSpecification is a IRequestSpecification implementation that identifies a request as a parameter of type ICalendarClient that belongs to the constructor of type CalendarService.
FixedRequestRelay is a simple ISpecimenBuilder that always resolves the same predefined request from ISpecimenContext instead of the received one.
Here's a very basic implementation of it.
public record FixedRequestRelay(object Request) : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
=> context.Resolve(this.Request);
}
Next you have your wrapper that also takes as a parameter an abstraction of type ICustomerClient. However this instance you want to be resolved as a mock that you can control from the test. Since you use AutoFixure.AutoMoq you can leave this one as is and let AutoMoq generate a mock for it.
Let's say this is the resulting customization.
public class CalendarCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(new TypeRelay(typeof(ICalendarService), typeof(CalendarService)));
fixture.Customizations.Add(new FilteringSpecimenBuilder(
new FixedRequestRelay(typeof(CalendarClientWrapper)),
new AndRequestSpecification(
new ParameterSpecification(typeof(ICalendarClient), "client"),
new ParameterMemberSpecification(
new DeclaringTypeSpecification(
new ExactTypeSpecification(typeof(CalendarService)))))));
}
}
By using it you can write a test like this.
[Theory, MyData]
public async Task Foo(
[MinLength(5)] Event[] events,
[Frozen] Mock<ICalendarClient> clientMock,
CalendarController controller,
DateTime start, DateTime end)
{
clientMock
.Setup(x => x.GetAllEvents(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(events);
var actual = await controller.GetAllEvents(start, end, default);
Assert.Equal(events, actual);
}
I have a code like this (I have to test a repo, you'll see the code below)
public class SomeClass
{
public AsyncPolicyWrap PropName { get; }
public SomeClass(...)
{
PropName = Policy.WrapAsync(someRetry,someCircuitBreaker)
// here there are passed some methods that return someRetry - AsyncRetryPolicy
// and someCircuitBreaker - AsyncCircuitBreakerPolicy
}
}
then I have another repo class
public class SomeRepo : ISomeRepo
{
private readonly AsyncPolicy _somePolicy;
public SomeRepo(..., SomeClass someClass) : base(...)
{
_somePolicy = someClass.PropName;
}
public async Task<Result<SomeDTO>> GetDTO(Guid someId)
{
var someResponse = await _somePolicy.ExecuteAsync(() =>
HttpClient.GetAsync(serviceName, $"endpointUrl"));
...
}
}
2 pieces of code above can't be changed cause they are in prod and I as a junior dev just have to cover code with tests if possible
I have tried to write a test like this
[TestMethod]
public async Task DoStuff()
{
var repository = DefaultSome();
var result = await repository.GetDTO(new Guid());
result.ShouldNotBeNull(); // don't pay attention I'll change stuff which has to be asserted
}
private SomeRepo DefaultSome(Some some = null)
{
some = some ?? A.Fake<ISome>();
/// HERE I TRIED TO MOCK STUFF IN DIFFERENT WAYS AND I HAVE AN ERROR
var policyWrap = A.Dummy<AsyncPolicyWrap>();
//var test = Policy.WrapAsync(A.Fake<AsyncRetryPolicy>(), A.Fake<AsyncCircuitBreakerPolicy>());
//var test = Policy.WrapAsync(A.Fake<IAsyncPolicy>(), A.Fake<IAsyncPolicy>());
A.CallTo(() =>
policyWrap.ExecuteAsync(A<Func<Task<HttpResponseMessage>>>._))
.Returns(new HttpResponseMessage(HttpStatusCode.OK));
var policy = A.Fake<RetryPolicies>();
A.CallTo(() =>
policy.PropName)
.Returns(policyWrap);
return new SomeRepo(some, ..., policy);
}
here is an error i get
I get similar for commented // var test = ... variats
Concrete vs Abstract
Whenever you need to mock something then rely on abstraction rather than concrete implementation.
AsyncPolicyWrap is a concrete class not an abstract like AsyncPolicy
Also as the exception says this class does not have a public parameterless constructor.
It has an internal ctor with 2 parameters:
internal AsyncPolicyWrap(AsyncPolicy outer, IAsyncPolicy inner)
: base(outer.ExceptionPredicates)
{
_outer = outer;
_inner = inner;
}
So, you should prefer AsyncPolicy abstract class or IAsyncPolicy interface.
With or without result
Please be aware that in Polly each Policy has two versions:
One which does not return any result
One which does return some result
Based on the SomeRepo's code your Policy should return an HttpResponseMessage.
So, you should use IAsyncPolicy<HttpResponseMessage> or AsyncPolicy<HttpResponseMessage> to indicate that your policy will return an HttpResponseMessage.
Mocking
Whenever you mock an IAsyncPolicy<HttpResponseMessage> then you don't have to recreate the combined policy (like you did in the comments). All you have to do is to define how should the ExecuteAsync behave.
Happy path:
var mockedPolicy = new Mock<IAsyncPolicy<HttpResponseMessage>>();
mockedPolicy
.Setup(policy => policy.ExecuteAsync(It.IsAny<Func<Task<HttpResponseMessage>>>()))
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));
Unhappy path:
var mockedPolicy = new Mock<IAsyncPolicy<HttpResponseMessage>>();
mockedPolicy
.Setup(policy => policy.ExecuteAsync(It.IsAny<Func<Task<HttpResponseMessage>>>()))
.ThrowsAsync(new HttpRequestException("Something bad happened"));
I've used moq to mock the policy but the same concept can be applied for FakeItEasy.
I have implemented an abstract generic repository that defines a set of methods for performing CRUD operations. I am trying to test them with the help of the Unit of Work pattern in a derived class. I'm using Moq as a testing framework and MockQueryable to enable Async operations like FirstOrDefaultAsync, AddAsync, SaveChangesAsync etc. I am experiencing an error testing the Add method. Here is a dummy project I created to show how things are set up.
DbContext Class
public class MyDBContextClass : DbContext, IDbContext
{
public MyDBContextClass(DbContextOptions options) : base(options) { }
public DbSet<Students> Students { get; set; }
}
Abstract class
public abstract class MyGenericRepository<TEntity> where TEntity : class
{
private readonly IDbContext context;
public MyMyGenericRepository(IDbContext context){
this.context = context;
}
public virtual async Task<int> Add(TEntity Entity)
{
await context.Set<TEntity>().AddAsync(entity); // throws a NullReferenceException during test
await context.SaveChangesAsync();
}
}
Unit of Work Class
public class StudentUnitOfWork : MyGenericRepository<Student>
{
public class StudentUnitOfWork(IDBContext context) : base(context)
{
}
}
The test class
public class StudentUnitOfWorkTest
{
[Fact]
public async Task Add()
{
var students = new List<Student>
{
new Student{ Id = 1, Name = "John Doe"},
new Student{ Id = 2, Name = "Jane Doe"}
}
var mockSet = students.AsQueryable().BuildMockDbSet();
var mockContext = new Mock<IDbContext>();
mockContext.Setup(_ => _.Students).Returns(mockSet.Object);
var sut = new StudentUnitOfWork(mockContext.Object);
var newStudentObj = new Student
{
Name = "Justin Doe"
}
await sut.Add(newStudentObj); // throws a NullReferenceException
mockSet.Verify(_ => _.AddAsync(It.IsAny<Student>(), It.IsAny<CancellationToken>()), Times.Once());
mockContext.Verify(_ => _.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once());
}
}
Overriding and injecting the base Add method also fails
public override async Task Add(Student student)
{
await base.Add(category); // Still throws a NullReferenceException
}
The test passes when I override the Implementation of Add in the Unit of Work Class and Set the actual dbSet in this case Students.
public class StudentUnitOfWork : MyGenericRepository<Student>
{
public override async Task Add(Student student)
{
await context.Students.AddAsync(student); // Works
await context.SaveChangesAsync();
}
}
Am I missing anything or DbContext.Set only works in production and not tests.
You are not configuring the Set method in IDbContext mock to return anything in your setup code, hence it returns null (default) and an exception is thrown when calling AddAsync.
Update:
Here's the line with error, where you call Set method:
await context.Set<TEntity>().AddAsync(entity);
And Here's your setup code in test, where you skip handling that same Set method:
var mockSet = students.AsQueryable().BuildMockDbSet();
var mockContext = new Mock<IDbContext>();
mockContext.Setup(_ => _.Students).Returns(mockSet.Object);
And since you are not mocking Set method, it returns null when test runs. You obviously cannot call AddAsync method on null, therefore NullReferenceException is thrown.
You should solve it by adding something like that:
mockContext.Setup(_ => _.Set<Student>()).Returns(<DbSet mock object>);
On the other hand,
await context.Students.AddAsync(student);
works, because you have mocked Students property
My WEB API project is using a Generic Repository that implements an interface like this:
public interface IGenericEFRepository<TEntity> where TEntity : class
{
Task<IEnumerable<TEntity>> Get();
Task<TEntity> Get(int id);
}
public class GenericEFRepository<TEntity> : IGenericEFRepository<TEntity>
where TEntity : class
{
private SqlDbContext _db;
public GenericEFRepository(SqlDbContext db)
{
_db = db;
}
public async Task<IEnumerable<TEntity>> Get()
{
return await Task.FromResult(_db.Set<TEntity>());
}
public async Task<TEntity> Get(int id)
{
var entity = await Task.FromResult(_db.Set<TEntity>().Find(new object[] { id }));
if (entity != null && includeRelatedEntities)
{
//Some Code
}
return entity;
}
}
Well now I want to test this service. for this I have used the following code:
public class CustomerControllerTest
{
CustomerController _controller;
ICustomerProvider _provider;
ICustomerInquiryMockRepository _repo;
public CustomerControllerTest()
{
_repo = new CustomerInquiryMockRepository();
_provider = new CustomerProvider(_repo);
_controller = new CustomerController(_provider);
}
[Fact]
public async Task Get_WhenCalled_ReturnsOkResult()
{
// Act
var okResult = await _controller.Get();
// Assert
Assert.IsType<OkObjectResult>(okResult);
}
[Fact]
public async Task GetById_UnknownCustomerIdPassed_ReturnsNotFoundResult()
{
// Act
var notFoundResult = await _controller.Get(4);
// Assert
Assert.IsType<NotFoundResult>(notFoundResult);
}
}
Which my tests are working fine by creating a fake non-generic service manually with mock data (In-Memory) like below, instead of using my real generic interface and it's implementation that uses my database as data-source:
public interface ICustomerInquiryMockRepository
{
Task<IEnumerable<CustomerDTO>> GetCustomers();
Task<CustomerDTO> GetCustomer(int customerId);
}
And it's implementation:
public class CustomerInquiryMockRepository : ICustomerInquiryMockRepository
{
public async Task<IEnumerable<CustomerDTO>> GetCustomers()
{
return await Task.FromResult(MockData.Current.Customers);
}
public async Task<CustomerDTO> GetCustomer(int CustomerId)
{
var Customer = await Task.FromResult(MockData.Current.Customers.FirstOrDefault(p => p.CustomerID.Equals(CustomerId)));
if (includeTransactions && Customer != null)
{
Customer.Transactions = MockData.Current.Transactions.Where(b => b.CustomerId.Equals(CustomerId)).ToList();
}
return Customer;
}
}
And the MockData.Current.Customers is just a simple fake (In-Memory) List of Customers. Long story short, the above tests are working fine, however I am feeling I have repeated my self a lot and so I have decided to use Moq library instead of creating fake service manually. For this purpose I have used Moq like this:
public class CustomerControllerTest
{
CustomerController _controller;
ICustomerProvider _provider;
//ICustomerInquiryMockRepository _repo;
Mock<ICustomerInquiryMockRepository> mockUserRepo;
public CustomerControllerTest()
{
mockUserRepo = new Mock<ICustomerInquiryMockRepository>();
//_repo = new CustomerInquiryMockRepository();
_provider = new CustomerProvider(mockUserRepo.Object);
_controller = new CustomerController(_provider);
}
[Fact]
public async Task Get_WhenCalled_ReturnsOkResult()
{
mockUserRepo.Setup(m => m.GetCustomers())
.Returns(Task.FromResult(MockData.Current.Customers.AsEnumerable()));
// Act
var okResult = await _controller.Get();
// Assert
Assert.IsType<OkObjectResult>(okResult);
}
[Fact]
public async Task GetById_UnknownCustomerIdPassed_ReturnsNotFoundResult()
{
//Arrange
I don't know how can I use Moq here and in the other parts of my tests
// Act
var notFoundResult = await _controller.Get(4);
// Assert
Assert.IsType<NotFoundResult>(notFoundResult);
}
Now my question is the Mock is working fine when I use it for Mocking the GetCustomers method because I simply paste the code from GetCustomers method in the CustomerInquiryMockRepository in the Returns method of the Mock object. However I don't really have any idea how can I use Mock for my other methods inside this Repository. Should I replace anything that I have in the Return method?
You can mock out your repository like so:
var mockUserRepo = new Mock<ICustomerInquiryMockRepository>();
mockUserRepo.Setup(x => x.GetCustomers())
.Returns(Task.FromResult(MockData.Current.Customers.AsEnumerable());
mockUserRepo.Setup(x => x.GetCustomer(It.IsAny<int>()))
.Returns(res => Task.FromResult(MockData.Current.Customers.ElementAt(res));
If you want to mock out specific values for GetCustomer, you can do:
mockUserRepo.Setup(x => x.GetCustomer(It.Is<int>(y => y == 4)))
.Returns(res => Task.FromResult(/* error value here */));
I think the key here is to use It.Is or It.IsAny based on how you want to mock out the object. Generally, you also want to mock out interfaces that are used in production code, instead of having production code depend on something with Mock or Test in the name. I would recommend against taking a production code dependency on something named ICustomerInquiryMockRepository, if that is indeed what you're doing and not just part of the MCVE you've provided.
Tests usually use mocking to test the workflow of an application at a high level, so you would usually want to mock out your services level, call a controller, and verify that the services were called as expected. For example:
// Production class sample
class ProductionController
{
public ProductionController(IService1 service1, IService2 service2) { }
public void ControllerMethod()
{
var service1Result = service1.Method();
service2.Method(service1Result);
}
}
// Test sample
// arrange
var expectedResult = new Service1Result();
var service1 = Mock.Of<IService1>(x => x.Method() == expectedResult);
var service2 = Mock.Of<IService2>(x => x.Method(It.Is<Service1Result>(y => y == expectedResult)));
var controller = new ProductionController(service1, service2);
// act
controller.ControllerMethod();
// assert
Mock.Get(service1).Verify(x => x.Method(), Times.Once);
Mock.Get(service2).Verify(x => x.Method(expectedResult), Times.Once);
As you can see from the example, you aren't checking the business logic of either of the services, you're just validating that the methods were called with the expected data. The test is built around verification of methods being called, not any particular branching logic.
Also, unrelated to your question, Moq also has a cool syntax you can use for simple mock setups:
var repo = Mock.Of<ICustomerInquiryMockRepository>(x =>
x.GetCustomers() == Task.FromResult(MockData.Current.Customers.AsEnumerable()));
You can use Mock.Get(repo) if you need to do additional setup on the repository. It's definitely worth checking out, I find it much nicer to read.
I've got a base ApiController for my controllers to inherit:
public BaseApiController(ILogger logger) : ApiController
{
private readonly ILogger _logger;
public BaseApiController(ILogger logger)
{
_logger = logger.ForContext("SomeContext");
}
}
And a simple controller that's inheriting from the base controller:
public SomeController : BaseApiController
{
public SomeController(ILogger logger) : base(logger)
{ }
public IHttpActionResult SomeAction()
{
_logger.Information("Start doing something...");
//Do stuff...
_logger.Information("End doing something...");
return Ok();
}
}
I've created a simple test for the controller using Xunit and Nsubstitute:
public void SomeAction_ReturnsOk()
{
//Arrange
var logger = Substitute.For<ILogger>();
var controller = new SomeController(logger) {
Request = Substitute.For<HttpRequestMessage>()
};
//Act
var result = controller.SomeAction();
//Assert
logger.ReceivedWithAnyArgs().Information(Arg.Any<string>());
}
When executing the test case, it fails stating that it has received zero calls to the logger.Information() method. When debugging the _receivedCalls property (on the substituted ILogger), if the debug context is within the test case itself it is showing a single call to the logger.ForContext() method (which was called on the base class constructor), however when looking at the debug within the context of the controller.SomeAction() method, the same _receivedCalls property shows the two calls to logger.Information() as would be expected but not the call to ForContext().
So it appears to me that for some reason Nsubstitute is creating two separate instances of the substitute class, one in the context of the base controller and one in the actual controller - why is this and how can I avoid it?
You need to stub the ForContext return like this:
public void SomeAction_ReturnsOk()
{
//Arrange
var logger = Substitute.For<ILogger>();
logger.ForContext(Arg.Any<string>()).Returns(logger);
var controller = new SomeController(logger) {
Request = Substitute.For<HttpRequestMessage>()
};
//Act
var result = controller.SomeAction();
//Assert
logger.Received().Information(Arg.Any<string>());
}
I change the assert to:
logger.Received().Information(Arg.Any<string>());
OR:
logger.ReceivedWithAnyArgs().Information("");