I'm having difficulties while trying to properly mock an arbitrary interface wrapped inside Lazy class.
I've tried:
[TestClass]
public class MyFooServiceTests
{
private Mock<Lazy<IFoo>> _lazyFooMock = new Mock<Lazy<IFoo>>();
private Mock<IFoo> _fooMock = new Mock<IFoo>();
private MyFooService _service;
[TestMethod]
public void FooMethod_HappyPath_ShouldReturn()
{
//Arrange
_fooMock
.Setup(x => x.DoSomething())
.Returns(1);
_lazyFooMock
.SetupGet(x => x.Value)
.Returns(_fooMock.Object); // --------> Throws Exception.
_service = new MyService(_lazyFooMock.Object);
}
}
public interface IFoo
{
int DoSomething();
}
public class MyFooService
{
public MyFooService(IFoo foo) { ... }
}
Exception Message:
Unsupported expression: x => x.Value
Non-overridable members (here: Lazy.get_Value) may not be used in setup / verification expressions.
Moq: 4.16.1
Solved by help of others, I've dumped the _lazyFooMock and replaced it with actual Lazy: _lazyFoo, and initiated it by the help of the overload: public Lazy(Func<T> valueFactory).
private Mock<IFoo> _fooMock = new Mock<IFoo>();
private Lazy<IFoo> _lazyFoo;
private MyFooService _service;
[TestMethod]
public void FooMethod_HappyPath_ShouldReturn()
{
//Arrange
_fooMock
.Setup(x => x.DoSomething())
.Returns(1);
_lazyFoo = new Lazy<IFoo>(() => _fooMock.Object);
_service = new MyFooService(_lazyFoo);
}
Related
private Mock<Icache<string>> _mockobj;
[TestInitialize]
public void Initialize()
{
_mockobj = new Mock<Icache<string>>();
}
[TestMethod]
public async Task methodName()
{
_mockobj.Setup(x => x.get("keyname", out id)).Returns(true);
_mockobj.Verify(x => x.get("keyname", out id), Times.Once());
}
Got an error on the verify statement the error is
Evaluation of method System.Linq.Expressions.Expression.Call requires calling method System.RuntimeType.get_IsCollectible
, which cannot be called in this context.
For the sake of brevity let's suppose we have the following stuffs:
public interface ICache<T>
{
void Get(string key, out T value);
}
class SystemUnderTest
{
private readonly ICache<string> cache;
public SystemUnderTest(ICache<string> cache)
=> this.cache = cache;
public void MethodUnderTest()
=> cache.Get("key", out var _);
}
So, the SystemUnderTest (SUT) class receives an ICache instance via constructor and uses it inside its MethodUnderTest.
Then your should look something like this:
//Arrange
var cacheMock = new Mock<ICache<string>>();
var expectedOutValue = "value";
cacheMock.Setup(c => c.Get("key", out expectedOutValue));
//Act
var sut = new SUT(cacheMock.Object);
sut.MethodUnderTest();
//Assert
cacheMock.Verify(c => c.Get("key", out expectedOutValue));
In the Arrange phase we setup the mock
In the Act phase we connect the mock and the SUT, then we call the method which uses the mock
Finally in the Assert phase we verify the usage of the mock
ILogger's usage in my controller's method.
public class MetaDataController
{
private readonly ILogger<MetaDataController> _logger;
public MetaDataController(ILogger<MetaDataController> logger)
{
_logger = logger;
}
public async Task<IActionResult> GetSearchFields()
{
_logger.LogInformation("Received request for GetSearchFields");
..
..
}
}
my test case method
public class MetaDataControllerTests
{
private readonly MockRepository _mockRepository;
private readonly Mock<ILogger<MetaDataController>> _mockloggerController;
public MetaDataControllerTests()
{
this._mockRepository = new MockRepository(MockBehavior.Strict);
this._mockloggerController = this._mockRepository.Create<ILogger<MetaDataController>>();
}
private MetaDataController CreateMetaDataController()
{
return new MetaDataController(this._mockMetaDataService.Object, this._mockloggerController.Object);
}
[Fact()]
public async Task GetSearchFields_WhenCalled_ReturnsSearchOptionsMetaData()
{
//Arrange
//First attempt
_mockloggerController.Setup(x => x.LogInformation(It.IsAny<string>(), It.IsAny<object[]>()));
//Second attempt
_mockloggerController.Setup(x => x.LogInformation(It.IsAny<string>()));
/* at above line of code getting the exception message.*/
//Act
var metaDataController = this.CreateMetaDataController();
var result = await metaDataController.GetFeasibilitySearchFields().ConfigureAwait(false);
//Assert
}
}
as mention in /**/ comment getting the below exception
Message: System.NotSupportedException : Unsupported expression: x =>
x.LogInformation(It.IsAny(), new[] { }) Extension methods
(here: LoggerExtensions.LogInformation) may not be used in setup /
verification expressions.
so how to mock exactly and prevent this exception ?
I have a question, I have a dependency that is resolved using the Func delegate, how can I use moq in this scenario?
public Func<string, IMylogic> MyLogic { get; set; }
The definition is this:
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddTransient(Factory);
}
private static Func<IServiceProvider, Func<string, IMyLogic>> Factory =>
service =>
{
return key =>
{
return new MyLogic(key, new System.Net.Http.HttpClient());
};
};
}
This is just an idea on how the test should work:
public class ExecuteEmitLogicTest
{
ExecuteTransactionCommand ExecuteEmitCommand;
Dictionary<string, StringValues> queryString;
Mock<Func<string, IMyLogic>> Concrete;
[Fact]
public async Task ExecuteEmit()
{
var Concrete = mockFactory.Create<Func<string, IMyLogic>>(MockBehavior.Loose);
Concrete.Setup(c => c.Invoke(ConcreteTInfo).Execute(request, Guid.Parse(sessionId))).Returns(Task.FromResult(pol));
ExecuteEmitCommand = new ExecuteTransactionCommand(Concrete.Object);
var response = await ExecuteEmitCommand.ExecuteAndEmit(queryString, ConcreteTInfo.ApiSkrUrl, ConcreteTInfo.SkrKey, FIXED_HASH);
Assert.True(response.IsValid);
}
}
I don't understand the redirection part with the <string, interface> function, but I would imagine the test to look more like this:
public interface IMyLogic { int GetX(); }
...
Mock<IMyLogic> mockLogic = new Mock<IMyLogic>(MockBehavior.Strict);
// For the unit test always return the mock as
// we are *not* testing the IMyLogic provider function
Func<string, IMyLogic> f = (string _) => mockLogic.Object;
mockLogic.Setup(ml => ml.GetX()).Returns(7);
var tested = new ExecuteTransactionCommand(f);
var response = await tested.ExecuteAndEmit(queryString, ConcreteTInfo.ApiSkrUrl, ConcreteTInfo.SkrKey, FIXED_HASH);
// Asserts here
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
I am practicing unit-testing a lot of these days, so bear with me if I fail to understand some basics.
Having these simple abstractions:
public interface ITaskFactory
{
void StartTask(Action action);
}
internal sealed class TaskFactory : ITaskFactory
{
public void StartTask(Action action)
{
Task.Factory.StartNew(action);
}
}
And this class to test (simplified to this case):
internal sealed class TriggerEventDecorator<TEvent> : ITriggerEvent<TEvent> where TEvent : IEvent
{
private readonly ITaskFactory _taskFactory;
private readonly Func<ITriggerEvent<TEvent>> _factory;
public TriggerEventDecorator(ITaskFactory taskFactory, Func<ITriggerEvent<TEvent>> factory)
{
_taskFactory = taskFactory;
_factory = factory;
}
public void Trigger(TEvent evt)
{
_taskFactory.StartTask(() =>
{
_factory().Trigger(evt);
});
}
}
And my test of this class:
public class TriggerEventDecoratorTests
{
[Fact]
public void CanTriggerEventHandler()
{
var evt = new FakeEventWithoutValidation();
Assert.IsAssignableFrom<IEvent>(evt);
var decorated = new Mock<ITriggerEvent<FakeEventWithoutValidation>>(MockBehavior.Strict);
decorated.Setup(x => x.Trigger(evt));
var taskFactory = new Mock<ITaskFactory>(MockBehavior.Strict);
taskFactory.Setup(factory => factory.StartTask(It.IsAny<Action>()));
var decorator = new TriggerEventDecorator<FakeEventWithoutValidation>(taskFactory.Object, () => decorated.Object);
decorator.Trigger(evt);
taskFactory.Verify(x => x.StartTask(It.IsAny<Action>()), Times.Once);
decorated.Verify(x => x.Trigger(evt), Times.Once); // This line is not verified
}
}
The line decorated.Verify(x => x.Trigger(evt), Times.Once); is not verified, it is never invoked.
How do I test that this is trigged in the Action of the _taskFactory?
You didn't invoke the Func method. This is the problem... To do so you'll have to use Callback method.
Change the following sertup:
taskFactory.Setup(factory => factory.StartTask(It.IsAny<Action>()));
To:
taskFactory.Setup(factory => factory.StartTask(It.IsAny<Action>()))
.Callback<Action>((action) => action());