How to Moq lazy interface in nunit? [duplicate] - c#

This question already has answers here:
Mock lazy interface with Moq
(3 answers)
Closed 1 year ago.
The system under test
public class AddDateRangeSaga : IDistributedSaga<AddDateRangeRequestModel, AddDateRangeResponseModel>
{
/// <summary>
/// AddDateRangeAr Inject
/// </summary>
public readonly Lazy<IAddDateRangeAr> _addDateRangesAr;
/// <summary>
/// For log and exception handling
/// </summary>
private readonly IApiRequestHandler _reqHandler;
public AddDateRangeSaga(IApiRequestHandler reqHandler
, Lazy<IAddDateRangeAr> addDateRangesAr)
{
_reqHandler = reqHandler;
_addDateRangesAr = addDateRangesAr;
}
public async Task<AddDateRangeResponseModel> Execute(AddDateRangeRequestModel request)
{
return await _addDateRangesAr.Value.AddDateRange(request);
}
}
The test case
public class AddDateRangeSagaTests
{
private Mock<IApiRequestHandler> _mockApiRequestHandler;
public Mock<Lazy<IAddDateRangeAr>> _addDateRangesAr;
private MockRepository mockRepository;
[SetUp]
public void SetUp()
{
mockRepository = new MockRepository(MockBehavior.Strict);
_mockApiRequestHandler = mockRepository.Create<IApiRequestHandler>();
_addDateRangesAr = mockRepository.Create<Lazy<IAddDateRangeAr>>();
}
private AddDateRangeSaga CreateAddDateRangeSagaTests()
{
return new AddDateRangeSaga(this._mockApiRequestHandler.Object, _addDateRangesAr.Object);
}
[Test]
public async Task AddDateRangeSaga_StateUnderTest_ExpectedBehavior()
{
//Arrange
var addDateRangeAr = this.CreateAddDateRangeSagaTests();
AddDateRangeRequestModel addDateRangeRequestModel = new AddDateRangeRequestModel();
AddDateRangeResponseModel addDateRangeResponseModel = new AddDateRangeResponseModel();
_addDateRangesAr.Setup(x => x.Value.AddDateRange(addDateRangeRequestModel)).ReturnsAsync(addDateRangeResponseModel);
var dd = addDateRangeAr.Execute(addDateRangeRequestModel);
//Assert
Assert.AreEqual(1,1); //dummy
}
}
Received error during execution
System.NotSupportedException : Unsupported expression: x => x.Value
Non-overridable members (here: Lazy.get_Value) may not be used in setup / verification expressions.
Problem
I am not able to figure out the exact issue with lazy moq. Can someone help me to figure out the issue?

First let me share with you the revised version of your test then the explanation.
public class AddDateRangeSagaTests
{
private Mock<IApiRequestHandler> apiRequestHandlerMock;
private Mock<IAddDateRangeAr> addDateRangesArMock;
private MockRepository mockRepository;
[SetUp]
public void SetUp()
{
mockRepository = new MockRepository(MockBehavior.Strict);
apiRequestHandlerMock = mockRepository.Create<IApiRequestHandler>();
addDateRangesArMock = mockRepository.Create<IAddDateRangeAr>();
}
private AddDateRangeSaga CreateAddDateRangeSagaTests()
{
var lazyAddDateRangesAr = new Lazy<IAddDateRangeAr>(() => addDateRangesArMock.Object);
return new AddDateRangeSaga(apiRequestHandlerMock.Object, lazyAddDateRangesAr);
}
[Test]
public async Task AddDateRangeSaga_StateUnderTest_ExpectedBehavior()
{
//Arrange
var sut = this.CreateAddDateRangeSagaTests();
addDateRangesArMock
.Setup(x => x.AddDateRange(It.IsAny<AddDateRangeRequestModel>()))
.ReturnsAsync(new AddDateRangeResponseModel());
//Act
var response = await sut.Execute(addDateRangeRequestModel);
//Assert
Assert.NotNull(response);
}
}
I've changed your _addDateRangesAr field to addDateRangesArMock
Here we are mocking the interface itself not the Lazy container
I've changed the visibility as well from public to private because this field should not be accessed by any other class
I've changed the name of _mockApiRequestHandler field to apiRequestHandlerMock to avoid using _ prefixes
Inside the CreateAddDateRangeSagaTests I've initialized a Lazy<IAddDateRangeAr> which will return the mocked IAddDateRangeAr whenever it's first accessed
I've simplified the mock setup and made it more generic
from .AddDateRange(addDateRangeRequestModel)
to .AddDateRange(It.IsAny<AddDateRangeRequestModel>())
I've called the Execute with await to be able to examine the response
I've used a simple null check to make sure it works as expected

Related

Expected invocation on Mock once, but was 0 times

I have an interface IVehicle
public interface IVehicle
{
Task<ApiResponse> GetVehicleInfo();
}
This is my implementation of the interface
public class Vehicle : IVehicle
{
private string m_vehicleId;
private VehicleInfoEndPoint m_vEndPoint;
public Vehicle()
{
}
public Vehicle(string vehicleId, string device, HttpClient client,string Uri)
{
m_vEndPoint = new VehicleInfoEndPoint(device, client, Uri);
}
public async Task<ApiResponse> GetVehicleInfo()
{
await m_vEndPoint.GetVehicleInfoPostAsync();
return m_vehicleInfoEndPoint.FullResponse;
}
}
I want to unit test this class. For that I have written the following code.
[Test]
public void Vehicle_GetVehicleInformation_shouldCall_VehicleInfoEndPoint_GetVehicleInfo()
{
var endPointMock = Mock.Of<IVehicleInfoEndPoint>();
var result = new ApiResponse();
var vehicle = new Mock<IVehicle>();
vehicle.Setup(x => x.GetVehicleInfo()).Returns(Task.FromResult(result));
var response = vehicle.Object.GetVehicleInfo().Result;
Mock.Get(endPointMock).Verify(x => x.GetVehicleInfo(), Times.Once);
}
My test is failing with the error that
Expected invocation on the mock once, but was 0 times x=> x.GetVehicleInfo()
In this case, it seems you want to test is that x.GetVehicleInfoPostAsync() is called.
Being this the case, you have to define your unit artifacts which are:
Vehicle is your system under test
IVehicleInfoEndPoint is your mock
You want to assert that calling GetVehicleInfo() calls the mock endpoint
I made this quick example that does what you want:
class Program
{
static async Task Main(string[] args)
{
// ARRANGE
var endPointMock = Mock.Of<IVehicleInfoEndPoint>();
var vehicle = new Vehicle(endPointMock);
// ACT
var response = await vehicle.GetVehicleInfo();
// ASSERT
Mock.Get(endPointMock).Verify(x => x.GetVehicleInfoPostAsync(), Times.Once);
}
}
public interface IVehicle
{
Task<ApiResponse> GetVehicleInfo();
}
public class Vehicle : IVehicle
{
private readonly IVehicleInfoEndPoint _endpoint;
public Vehicle(IVehicleInfoEndPoint endpoint)
{
_endpoint = endpoint ?? throw new ArgumentNullException(nameof(endpoint));
}
public async Task<ApiResponse> GetVehicleInfo()
{
await _endpoint.GetVehicleInfoPostAsync();
return _endpoint.FullResponse;
}
}
public interface IVehicleInfoEndPoint
{
Task GetVehicleInfoPostAsync();
ApiResponse FullResponse { get; set; }
}
public class ApiResponse
{
}
It helps when you divide your test into 3 parts:
Arrange
Act
Assert
Check this out: What is a "Stub"?
Also, checkout "The art of unit testing" on Amazon, great book.

How to write xUnit Test for a method which calls another method in its body?

This is the class contains EnqueueJobAsync method which I want to write test for it :
public class ConsumerBaseForTesting
{
protected IJobStore JobStore { get; private set; }
public ConsumerBaseForTesting(IJobStore jobStore)
{
JobStore = jobStore;
}
public async Task<IJob> EnqueueJobAsync(IJob job)
=> await JobStore.CreateAsync(job);
}
This is my test which Fails and its actual return is always NULL !
public class ConsumerBaseTest
{
private readonly Mock<IJobStore> _moqIJobStore;
private readonly ConsumerBaseForTesting _consumerBase;
public ConsumerBaseTest()
{
_moqIJobStore = new Mock<IJobStore>();
_consumerBase = new ConsumerBaseForTesting(_moqIJobStore.Object);
}
[Theory]
[ClassData(typeof(JobClassForTesting))]
public async Task EnqueueJobAsyncTest(IJob job)
{
var jobResult = await _consumerBase.EnqueueJobAsync(job);
Assert.Equal(job, jobResult);
}
}
The mock needs to be setup to do two things in order to replicate the expected behavior.
It needs to return the passed job in a completed task.
//...
public ConsumerBaseTest() {
_moqIJobStore = new Mock<IJobStore>();
_consumerBase = new ConsumerBaseForTesting(_moqIJobStore.Object);
//setup the mock to capture and return the job when CreateAsync(IJob job) is invoked
_moqIJobStore
.Setup(_ => _.CreateAsync(It.IsAny<IJob>()))
.Returns((IJob x) => Task.FromResult(x)); }
//...
.Returns((IJob x) => Task.FromResult(x)) captures the argument and returns completed Task<IJob>

Cannot unit test a class with a method returning RedisResult with StackExchange.Redis

I have a simple wrapper for stackexchange redis:
public interface IRedisClient
{
Task<RedisResult> ScriptEvaluate(LuaScript script, object parameters);
}
I have a method that calls ScriptEvaluate
public class Foo
{
private readonly IRedisClient _client;
public Foo(IRedisClient client)
{
_client = client;
}
public void RunScript()
{
_client.ScriptEvaluate(LuaScript.Prepare(""), new object());
}
}
Now when I use NSubstitute to mock IRedisClient that is injected to Foo and then call RunScript
public void Test()
{
_foo = new Foo(Substitute.For<IRedisClient>());
_foo.RunScript();
}
I get the following error:
System.TypeLoadException: Method 'AsBoolean' in type
'Castle.Proxies.RedisResultProxy' from assembly
'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=a621a9e7e5c32e69' does not have an implementation.
As far as I can see Nsubstitute/Castle internals do not manage to work with RedisResult properly. I did not manage to find out any workarounds.
Is it possible to do something with this?
P.S. I get the same error when I try to configure the mock to return a value (same exception):
_client
.ScriptEvaluate(null, null)
.ReturnsForAnyArgs(RedisResult.Create((RedisKey)"result"));
I was curious about why mocking the abstract RedisResult was not a simple solution.
This appears to be an issue with NSubstitute's implementation.
Using the following to try and recreate the problem
public class Foo {
private readonly IRedisClient _client;
public Foo(IRedisClient client) {
_client = client;
}
public Task<RedisResult> RunScript() {
return _client.ScriptEvaluate(LuaScript.Prepare(""), new object());
}
}
I was able to reproduce it using NSubstitute but was able to exercise the test to completion when using another mocking framework (MOQ)
[TestClass]
public class MyTestClass {
[TestMethod]
public async Task Test1() {
//Arrange
var expected = RedisResult.Create((RedisKey)"result");
var _client = Substitute.For<IRedisClient>();
_client
.ScriptEvaluate(Arg.Any<LuaScript>(), Arg.Any<object>())
.Returns(expected);
var _foo = new Foo(_client);
//Act
var actual = await _foo.RunScript();
//Assert
actual.Should().Be(expected);
}
[TestMethod]
public async Task Test2() {
//Arrange
var expected = RedisResult.Create((RedisKey)"result");
var _client = Mock.Of<IRedisClient>(_ => _.ScriptEvaluate(It.IsAny<LuaScript>(), It.IsAny<object>()) == Task.FromResult(expected));
var _foo = new Foo(_client);
//Act
var actual = await _foo.RunScript();
//Assert
actual.Should().Be(expected);
}
}
RedisResult is an abstract type, but there are static Create methods for common scenarios, and a few static properties such as EmptyArray, NullArray, etc. I can't tell you how to configure your particular faking layer, but ultimately, I'd expect something involving RedisResult.Create

Getting exception with Moq when trying to test Task

I'm trying to use Moq (4.10) on async calls but I cannot get the hang of it.
Search on how to do so and found answers which I've tried but I cannot make it to work .
This is my test
public class Test
{
[Fact]
public void Test_Create()
{
var repositoryMock = new Mock<IRepository>();
repositoryMock
.Setup(repo => repo.CreateAsync(It.IsAny<Aggregate >()))
.Returns(Task.CompletedTask);
/// also tried this
/// => .Returns(Task.FromResult(default(object)))
/// and
/// => .Returns(Task.FromResult(false)));
var useCase = new CreateUseCase(repositoryMock.Object);
Task.Run(async () => { await useCase.HandleAsync(new CreateRequest()); });
repositoryMock.VerifyAll();
}
}
resources
How can I tell Moq to return a Task?
Getting this exception
Moq.MockException: 'The following setups on mock
'Mock<.Repository.IRepository:00000001>' were not matched: IRepository
repo => repo.CreateAsync(It.IsAny < Aggregate>())
The repo looks like this
public interface IRepository
{
Task CreateAsync(Aggregate aggregate);
}
The UseCase
public class CreateUseCase : IUseCaseHandler<CreatRequest>
{
private IRepository _repository;
public CreateUseCase (IRepository repository)
{
_repository= repository?? throw new System.ArgumentNullException(nameof(repository));
}
public async Task HandleAsync(CreateRequest request, CancellationToken? cancellationToken = null)
{
Aggregate aggregate = new Aggregate();
aggregate.Create();
await _repository.CreateAsync(aggregate);
}
}
The Repository
public sealed class OrderRepository : ProxyRepository<OrderAggregate>, IOrderRepository
{
public OrderRepository(IUnitOfWork unitOfWork, INotificationDispatcher eventHandler)
: base(unitOfWork, eventHandler)
{
}
async Task IRepository.CreateAsync(Aggregate aggregate)
{
await base.AddAsync(aggregate);
}
}
What is it that I'm doing wrong or missing ?
We normally do not have to mock a method of an interface which doesn't return any unless I'm missing something in your question.
public class CreateUseCaseTests
{
[Fact]
public async Task HandleAsync_ShouldCreateRequest()
{
// Arrange
var repositoryMock = new Mock<IRepository>();
var sut = new CreateUseCase(repositoryMock.Object);
// Act
await sut.HandleAsync(new CreateRequest());
// Assert
repositoryMock.Verify(x => x.CreateAsync(It.IsAny<Aggregate>()), Times.Once);
}
}
I don't think your problem is with the Moq setup at all. The problem is that the unit test runs the meaningful code using Task.Run(), which spawns off a new thread. Then back on the original thread, you immediately test whether the Moq setup has been fulfilled. Since the code under test is launched on a different thread, there is a very real chance that the test for success comes before the code under test is executed.
You should change your unit test to run the test method using async & await, rather than spinning off a new thread. Note that the signature of the test case changes from void to async Task, and we await the code we're testing.
public class Test
{
[Fact]
public async Task Test_Create()
{
var repositoryMock = new Mock<IRepository>();
repositoryMock
.Setup(repo => repo.CreateAsync(It.IsAny<Aggregate >()))
.Returns(Task.CompletedTask);
var useCase = new CreateUseCase(repositoryMock.Object);
await useCase.HandleAsync(new CreateRequest());
repositoryMock.VerifyAll();
}
}

C# mocking generic repository using Moq

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

Categories