Home > Mobile >  Mocking IEnumerable<T> for each class that implements <T> using Moq
Mocking IEnumerable<T> for each class that implements <T> using Moq

Time:03-03

I have the following interface

public interface ICommand<TResult, TModel>
{
    Task<TResult> DoWorkAsync(TModel model);
}

Which is implemented by one or more such Command classes:

public class MyCommand1 : ICommand<Response, Model>()
{
    public async Task<Response> DoWorkAsync(Model model) {
        // do something
    }
}

public class MyCommand2 : ICommand<Response, Model>()
{
    public async Task<Response> DoWorkAsync(Model model) {
        // do something else
    }
}

The Respose and Model classes are as follows:

public class Response
{
    public bool IsSuccessful {get;set;}
}

public class Model
{
    public Guid Id {get;set;}
    public string Name {get;set;}
}

Then I have an orchestrator class that has a dependency on an IEnumerable of IEnumerable<ICommand<Response, Model>>

public class MyOrchestrator
{
    private readonly IEnumerable<ICommand<Response, Model>> _commands;

    public MyOrchestrator(IEnumerable<ICommand<Response, Model>> commands)
    {
        _commands = commands;
    }

    public async Task ExecuteAsync(Model model)
    {
        myCommand1_Response = await _commands
                                    .OfType<MyCommand1>()
                                    .First()
                                    .DoWorkAsync(model);

        myCommand2_Response = await _commands
                                    .OfType<MyCommand2>()
                                    .First()
                                    .DoWorkAsync(model);

        // other operations
    }
}

Now in my test I'm trying to mock the MyOrchestrator class's dependency IEnumerable<ICommand<Response, Model>> for each of the MyCommand types. How can I achieve this?

CodePudding user response:

The problem is that MyCommand2 and MyCommand1 are concrete classes. You'll either need to make them be IMyCommand1 and IMyCommand2 or make DoWorkAsync virtual.

CodePudding user response:

I think you could simplify your orchestator which would make mocking trivial.

public class MyOrchestrator
{
    ...

    public MyOrchestrator(ICommand<Response, Model> command1, ICommand<Response, Model> command2)
    {
        this.command1 = command1 ?? throw...;
        this.command2 = command2 ?? throw...;
    }

    public async Task ExecuteAsync(Model model)
    {
        myCommand1_Response = await command1.DoWorkAsync(model);

        myCommand2_Response = await command1.DoWorkAsync(model);

        // other operations
    }
}

Now mocking this is nothing special.

var mockCommand1 = new Mock<ICommand<Response, Model>>(MockBehaviour.Strict);
...

var tested = new MyOrchestrator(command1: mockCommand1.Object, ...); 
  • Related