Home > OS >  Moq for Interface that Inherits from ICollection returns null
Moq for Interface that Inherits from ICollection returns null

Time:06-13

I am trying to run unit tests using Moq. I am fairly new to Moq and I have ran into a problem with this current unit test. I have a controller that is fetching some items. The result is encapsulated within a generic interface using ICollection.

public interface IResult
{
}

public interface IListResult : ICollection<IResult>
{
}

My controller is simply calling a method that returns the result.

[HttpGet("get/{userId}/{pageSize}/{fetchNext}")]
public IActionResult GetConversations(int userId, int pageSize, bool fetchNext)
{
    try
    {
        GetConversationsByUserIdQuery query = new GetConversationsByUserIdQuery()
        {
            UserId = userId,
            PageSize = pageSize,
            FetchNext = fetchNext
        };
        var result = _mediator.GetConversationsByUserId(query);
        return Ok(result);
    }
    catch (Exception ex)
    {
        return StatusCode(StatusCodes.Status500InternalServerError, ex.Message);
    }
  }
}

When I am running my unit test, the result always comes back null and I am failing to understand what I am missing in my set up.

[Theory]
[InlineData(1, 2 , false)]
[InlineData(1, 2 , true)]
public async void When_AddMessageToNewConversation_ThenSuccessfullyAdd(int userId, int pageSize, bool fetchNext)
{
    // Arrange
    Mock<IMessageMediator> _mediator = new Mock<IMessageMediator>();
    Mock<IListResult> _listResult = new Mock<IListResult>();
    
    GetConversationsByUserIdQuery query = new GetConversationsByUserIdQuery()
    {
        UserId = userId,
        PageSize = pageSize,
        FetchNext = fetchNext
    };


    List<Conversation> expected = new List<Conversation>()
    {
        new Conversation()
        {
            Id = Guid.NewGuid(),
            Created_At = DateTimeOffset.Now
        }
    };

    _listResult.Setup(x => 
        x.GetEnumerator())
        .Returns(expected.GetEnumerator());

    GetConversationsByUserIdController controller = new GetConversationsByUserIdController(_mediator.Object);
    _mediator.Setup(x => 
        x.GetConversationsByUserId(query)).Returns(_listResult.Object);

    // Act
    IActionResult result = controller.GetConversations(userId, pageSize, fetchNext);

    // Assert
    Assert.True(result is OkResult);
}

The IMessageMediator is simply a delegator that handles implementation of queriers and commands. The IListResult is returned from a querier handler.

public class GetConversationsByUserIdQueryHandler: 
IQueryHandler<GetConversationsByUserIdQuery>
{
   private IRepository<Conversations_By_UserId> 
  _conversationByUserIdRepository;
  private IListResult _result;

public GetConversationsByUserIdQueryHandler(IRepository<Conversations_By_UserId> conversationByUserIdRepository,
    IListResult result)
{
    _conversationByUserIdRepository = conversationByUserIdRepository;
    _result = result;
}

public IListResult Handle(GetConversationsByUserIdQuery query)
{
    IEnumerable<Conversations_By_UserId> conversations = _conversationByUserIdRepository
        .Get(query.PageSize,
            query.FetchNext,
            message => message.UserId == query.UserId).ToList();
    
    if (conversations.Any())
    {
        foreach (Conversations_By_UserId m in conversations)
        {
            _result.Add(new Conversation()
            {
                Created_At = m.Created_At,
                Id = m.Id,
            });
        }
    }
    return _result;
  }
}

CodePudding user response:

You don't need to mock both IMessageMediator and IListResult.

You should mock dependencies - it is IMessageMediator in your case - and your can setup it to return any result.

The other thing - you mock _mediator using query created in test, but in controller you create different query (references are different) and it is the reason of null result.

Change your test:

[Theory]
[InlineData(1, 2 , false)]
[InlineData(1, 2 , true)]
public async void When_AddMessageToNewConversation_ThenSuccessfullyAdd(int userId, int pageSize, bool fetchNext)
{
    // Arrange
    Mock<IMessageMediator> _mediator = new Mock<IMessageMediator>();     

    List<Conversation> expected = new List<Conversation>()
    {
        new Conversation()
        {
            Id = Guid.NewGuid(),
            Created_At = DateTimeOffset.Now
        }
    };    
      
    GetConversationsByUserIdController controller = new GetConversationsByUserIdController(_mediator.Object);

             // It.IsAny<GetConversationsByUserIdQuery>()) instead of query
   _mediator.Setup(x => x.GetConversationsByUserId(It.IsAny<GetConversationsByUserIdQuery>()))

            // create fake result to return from mediator (no need to mock IListResult     
            .Returns(new ListResult() ...); // just create instance of IListResult with needed values

    // Act
    IActionResult result = controller.GetConversations(userId, pageSize, fetchNext);

    // Assert
    Assert.True(result is OkResult);
}
  • Related