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());
Related
I have a function which contains validation that check whether a variable value is null or not. I want to test that class method using xunit test. But due to this validation, I failed to call the Unit Test.
Class
public interface ICountry<CountryModel>
{
Task ProcessCall(IList<string> countryCodes);
}
public class CallOptions
{
public string Name { get; set; }
}
public class Country<CountryModel> : ICountry<CountryModel>
{
private readonly CallOptions _options;
private readonly Irepo _repo;
public Country(IOptions<CountryModel> options,Irepo repo)
{ _repo= repo
_options = options.Value;
if (string.IsNullOrWhiteSpace(_options.Name))
{
throw new ArgumentException("Missing name");
}
}
public async Task ProcessCall(IList<string> Codes)
{
_repo.set(Codes);
}
Unit Test
public class ProcessorTests
{
private Mock<Irepo> _RepositoryMock;
private Mock<IOptions<CallOptions>> options;
public ProcessorTests()
{
_RepositoryMock = new Mock<Irepo>();
options = new Mock<IOptions<CallOptions>>();
options.SetReturnsDefault("test");
}
private Country<CountryModel> CreateSut()
{
return new Country<CountryModel>(_RepositoryMock.Object, _options.Object);
}
[Fact]
public async Task ShouldCheck()
{
GetRepoMock();
await CreateSut().ProcessCall(new string[] { "TEST" });
_RepositoryMock.Verify(x => x.set(It.IsAny<List<string>>()), Times.Once);
}
private void GetRepoMock()
{
_RepositoryMock
.Setup(m => m.set(It.IsAny<List<string>>())
.ReturnsAsync(new Response<Code>(false, null, Enumerable.Empty<Code>()));
}
But when the unit test executes, the value of _options.Name is empty and failed the test while called the Country method.
Any idea regarding this?
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
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);
}
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>
I want to register consumer by interface, send message, initialize it by interface from container, then consume:
public sealed class TestConsumer<T> : IConsumer<T>
where T : class
{
private readonly Func<ConsumeContext<T>, Task> _onConsume;
private readonly EventWaitHandle _handle;
public TestConsumer(Func<ConsumeContext<T>, Task> onConsume)
{
_onConsume = onConsume;
_handle = new EventWaitHandle(false, EventResetMode.ManualReset);
}
public async Task Consume(ConsumeContext<T> context)
{
try
{
await _onConsume(context).ConfigureAwait(false);
}
finally
{
_handle.Set();
}
}
public async Task GetTask()
{
while (!_handle.WaitOne(0))
await Task.Delay(100);
}
}
public class MyRequest { }
[TestFixture]
public class ConsumerTests
{
[Test]
public async Task Test()
{
var services = new ServiceCollection();
var tc = new TestConsumer<MyRequest>(async (c) => Console.WriteLine("request"));
services.AddSingleton<IConsumer<MyRequest>>(tc);
services.AddSingleton<IBusControl>(x => Bus.Factory.CreateUsingInMemory(cfg =>
{
cfg.ReceiveEndpoint("foobar", c => { c.Consumer<IConsumer<MyRequest>>(x); });
}));
var sp = services.BuildServiceProvider();
await sp.GetRequiredService<IBusControl>().StartAsync();
//and how do I send it?
//this will obviously not work with Uri!!!
var sendEndpoint = await sp.GetRequiredService<IBusControl>().GetSendEndpoint(new Uri("foobar", UriKind.Relative));
await sendEndpoint.Send(new MyRequest());
await tc.GetTask();
Console.WriteLine("done");
}
}
Honestly, lack of documentation is driving me crazy. There is such thing as harness, but it works only if you throw your DI container into garbage can or write a ton of adapters.
How do one can use InMemory and combine it to completely uncompatible Uri in Send method?