Reputation: 376
I have an interface and implementation like so:
public interface IScopedServices
{
Task<TReturn> ExecuteAsync<TService, TReturn>(Func<TService, Task<TReturn>> action);
}
//Implemented like so:
public async Task<TReturn> ExecuteAsync<TService, TReturn>(Func<TService, Task<TReturn>> action)
{
using (var serviceScope = serviceScopeFactory.CreateScope())
{
var service = serviceScope.ServiceProvider.GetService<TService>();
return await action.Invoke(service);
}
}
This service wraps other service calls so they can get their own scope, an example of such a service call is:
public class TicketService : ITicketService
{
public async Task<Ticket> GetTicket(string ticketNumber)
{
return await repository.Get(t => t.TicketNumber == ticketNumber);
}
}
And this is called in my code under test like so:
var ticket = await ScopedServices.ExecuteAsync<ITicketService, Ticket>(s => s.GetTicket("ticket number"));
So in my unit test, I mock it like this, and it works fine, no problem:
var mockScopedServices = new Mock<IScopedServices>();
mockScopedServices.Setup(mss => mss.ExecuteAsync(It.IsAny<Func<ITicketService, Task<Ticket>>>())).ReturnsAsync(TestTicket);
My question is: how can I mock the ITicketService
so that when GetTicket
it is called with a specific parameter, I return a separate object?
Right now, as I'm new to Moq, I am not sure how to mock the ITicketService
so that I have control of what GetTicket
takes as an argument and therefore what it returns in such a case.
Upvotes: 4
Views: 1033
Reputation: 247058
You can use Callback
to capture the passed in delegate and then invoke it.
This will, to an extent, be mocking the internal workings of the implementation.
But the same can actually be done within the Returns
delegate
var scopedMock = new Mock<ITicketService>();
scopedMock
.Setup(_ => _.GetTicket(It.IsAny<string>())) // <-- setup and adjust as needed
.ReturnsAsync(TestTicket);
var mockScopedServices = new Mock<IScopedServices>();
mockScopedServices
.Setup(_ => _.ExecuteAsync(It.IsAny<Func<ITicketService, Task<Ticket>>>()))
.Returns((Func<ITicketService, Task<Ticket>> arg) => {
//this invokes the passed in delegate using the mocked scoped service
Task<Ticket> task = arg(scopedMock.Object);
return task;
});
Upvotes: 1