Search code examples
c#asp.net-corexunitfluent-assertionsmediatr

How to test MediatR handlers in XUnit with FluentAssertions


I am using XUnit for testing my ASP.NET Core 2.2 project.

Along with it, I have FluentAssertions in the test project.

What I want to do is to test my MediatR handler.

Inside this handler I have API call.

I have read through articles and it seems that I need to set up fixture first, but I have not found code easy for me to follow.

My Handler looks like:

     public class GetCatsHandler : IRequestHandler<GetCatsQuery, GetCatsResponse>
{
    private readonly IPeopleService _peopleService;

    public GetCatsHandler(IPeopleService peopleService)
    {
        _peopleService = peopleService;
    }

    public async Task<GetCatsResponse> Handle(GetCatsQuery request, CancellationToken cancellationToken)
    {
        var apiResponse = await _peopleService.GetPeople();
        List<Person> people = apiResponse;

        var maleCatsGroup = GetCatsGroup(people, Gender.Male);
        var femaleCatsGroup = GetCatsGroup(people, Gender.Female);

        var response = new GetCatsResponse()
        {
            Male = maleCatsGroup,
            Female = femaleCatsGroup
        };

        return response;
    }

    private static IEnumerable<string> GetCatsGroup(IEnumerable<Person> people, Gender gender)
    {
      .....
    }
}

PeopleService is the service class which has HttpClient and calls the API to retrieve result.

Here is my fixture:

public class GetCatsHandlerFixture : IDisposable
{
    public TestServer TestServer { get; set; }
    public HttpClient Client { get; set; }

    public GetCatsHandlerFixture()
    {
        TestServer = new TestServer(
            new WebHostBuilder()
            .UseStartup<Startup>()
            .ConfigureServices(services => {
            }));

        Client = TestServer.CreateClient();
    }
    public void Dispose()
    {
        TestServer.Dispose();
    }
 }

From here, how can I pass in my mock data for the api calls in different scenarios?


Solution

  • I ended up to use Moq to replace my PeopleService and appoint the designed return objects for testing.

    It works amazing and easy to use.

    so it looks like:

      mockPeopleService = new Mock<IPeopleService>();
      var people = ....;
    
                var expectedResult = new GetCatsResponse()
                {
                    Male = new List<string>() { "Garfield", "Jim", "Max", "Tom" },
                    Female = new List<string>() { "Garfield", "Simba", "Tabby" }
                };
    
                mockPeopleService.Setup(ps => ps.GetPeople()).Returns(people);
    
                var handler = new GetCatsHandler(mockPeopleService.Object);
    
                var actualResult = await GetActualResult(handler);
    
                actualResult.Should().BeEquivalentTo(expectedResult, optons => optons.WithStrictOrdering());