1

I am new to unit testing,

I am working on a minimal API project. and I am testing an endpoint with xunit, moq

endpoint class - ParticipantsGetAll.cs

public class ParticipantsGetAll : IEndpoint<IResult, GetAllParticipantsRequest>
{
    const string uri = "api/participants-all";
    private ParticipantService? participantService;

    public void AddRoute(IEndpointRouteBuilder app)
    {
        app.MapPost(uri, async ( ParticipantService participantService, [FromBody] GetAllParticipantsRequest query) => 
        {
            this.participantService = participantService;
            return await HandleAsync(query);
        })
        .Produces<List<ParticipantSummaryModel>>()
        .WithTags("Participants")
        .WithName("GetAllParticipants");
    }

    public async Task<IResult> HandleAsync( GetAllParticipantsRequest query)
    {
        var participants = await participantService!.ListAllAsync(query);
        return Results.Ok(participants);
    }

I tried to write a unit test test above endpoint class.

CreateParticipantApiTest.cs

    [Fact]
    public async void ListAllAsyncShouldReturn200Status()
    {
        var query = new GetAllParticipantsRequest()
        {
           Name= "",
            KeyCordinator="",
            RelatedConnection="",
            Statuses = null

        };
        var participant = ParticipantMockData.NewParticipantModel(); // a static class

        var sut = new ParticipantsGetAll();
        var result = (OkObjectResult)await sut.HandleAsync(query);

        result.StatusCode.Should().Be(200);

    }

I got below error

Message:  System.NullReferenceException : Object reference not set to an instance of an object.
Stack Trace:  ParticipantsGetAll.HandleAsync(GetAllParticipantsRequest query) line 36 CreateParticipantApiTest.ListAllAsyncShouldReturn200Status() line 67

I have no idea why the object tis null.

Please anyone help me to find the problem. I am facing this issue for a long time

Thanks

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
hanushi
  • 1,169
  • 2
  • 12
  • 27

1 Answers1

1

I have no idea why the object tis null.

That is pretty clear, because in your unit test you invoke HandleAsync directly, so the setup which you have moved into MapPost does not happen (compiler was trying to help but was shut down with null-forgiving operator in participantService!.ListAllAsync(query)). Also I'm pretty sure this way of using handlers can lead to some concurrency problems (if ParticipantService is a scoped service). Move ParticipantService participantService to HandleAsync. Something along this lines (not tested):

public class ParticipantsGetAll : IEndpoint<IResult, GetAllParticipantsRequest>
{
    const string uri = "api/participants-all";

    public void AddRoute(IEndpointRouteBuilder app)
    {
        app.MapPost(uri, HandleAsync)
        .Produces<List<ParticipantSummaryModel>>()
        .WithTags("Participants")
        .WithName("GetAllParticipants");
    }

    public async Task<IResult> HandleAsync(ParticipantService participantService, [FromBody] GetAllParticipantsRequest query)
    {
        var participants = await participantService.ListAllAsync(query);
        return Results.Ok(participants);
    }
}

And modify the test accrodingly.

halfer
  • 19,824
  • 17
  • 99
  • 186
Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • Thanks. Can I create a constructor inside `ParticipantsGetAll` like below. `public ParticipantsGetAll(ParticipantService participantService) { this.participantService = participantService; }` – hanushi Dec 21 '22 at 05:19
  • @hanushi you can but there is no point in doing so in current code structure. – Guru Stron Dec 21 '22 at 13:35