Masstransit Mediator Unit Test with Comprehensive Code Coverage

Last Update: August 13, 2024
Feature image of Masstransit Mediator Unit Test with Comprehensive Code Coverage
Table of Contents
Contributors
Picture of Vivasoft Team
Vivasoft Team
Tech Stack
0 +
Want to accelerate your software development company?

It has become a prerequisite for companies to develop custom software products to stay competitive.

This article explores the complexities of unit testing the Masstransit Mediator Consumer, highlighting the importance of attaining thorough code coverage. Utilizing the Masstransit Mediator Unit Test enables developers to ensure their messaging components function correctly across different scenarios, thus enhancing the stability and performance of their applications.

A unit test is a piece of code that you write to assess your application’s code. Your web application won’t be aware of your test project, but your test project will rely on the application project it’s evaluating.

Thus, thoroughly testing your code aids in preventing bugs from reaching production. This article will guide you through unit testing an ASP.NET Core Web API and an MVC application.

But you can also hire .NET Developers for your project to Masstransit Mediator unit test with comprehensive code coverage.

Prerequisites

I anticipate that you possess familiarity with object-oriented programming principles in C#. Additionally, I presume you are acquainted with .NET Core API concepts, particularly the MVC pattern. Here some tools should be needed.

  1. Dotnet SDK 8

  2. Visual Studio

What is Masstransit?

Masstransit stands out as an open-source messaging library crafted for the .NET ecosystem. It specializes in facilitating communication and secure data exchange among applications, particularly in the domain of asynchronous and distributed applications.

This article will delve into harnessing the MassTransit library’s capabilities to construct resilient and scalable distributed applications.

Masstransit Mediator

CQRS, short for Command and Query Responsibility Segregation, is a pattern that divides read and update operations for a data store. Masstransit also offers support for this pattern. To implement CQRS, a separate consumer is necessary.

Therefore, in this article, we demonstrate how to test the consumer while achieving code coverage. Before writing any unit testing code, it’s essential to understand which project is being utilized for testing purposes.

Now, I’ll provide some code that we’ll be testing in this article. To begin, establish a .NET API project by following these steps.

Step 1: Create a project

Create a project .NET API for Masstransit Mediator unit test

Step 2: Give your project name as well.

Give a name to the .NET API project

Step 3: Provide additional information.

Give additional information to the project

Step 4: Now, let’s install some NuGet packages into your project.

Install some NuGet packages into the project

Step 5: Now, this code provides a service (TestService) that generates a sequence of integers within a specified range. The interface ITestService defines the contract for this service, allowing for abstraction and easier dependency management.

				
					public interface ITestService
{
    IEnumerable<int> GetRangedNumbers(int number);
}
 
public class TestService : ITestService
{
    public TestService() { 
 
    }
 
    public IEnumerable<int> GetRangedNumbers(int number)
    {
        return Enumerable.Range(0, number);
    }
}
				
			

Step 6: Now create a DTO for the request filter

				
					public class TestDTO
{
    public int Limit { get; init; }
}
				
			

Step 7: This code configures Masstransit for in-memory messaging and Mediator for handling message consumers. It also registers TestService as a scoped service.

				
					builder.Services.AddMassTransit(cfg =>
{
    cfg.SetKebabCaseEndpointNameFormatter();
 
    cfg.UsingInMemory((context, config) =>
    {
        config.ConfigureEndpoints(context);
    });
});
 
builder.Services.AddMediator(cfg =>
{
    cfg.AddConsumers(AppDomain.CurrentDomain.Load("MasstransitConsumer"));
});
builder.Services.AddScoped<ITestService, TestService>();
				
			

Step 8: This class TestConsumer implements the Masstransit IConsumer<TestDTO> interface, indicating that it consumes messages of type TestDTO. Inside the Consume method, it retrieves a range of random numbers using the injected ITestService, based on the Limit property of the consumed message.

Finally, it responds asynchronously with a TestResponse containing the generated random numbers.

				
					public class TestResponse
{
    public IEnumerable<int> Data { get; set; }
}
				
			
				
					public class TestConsumer : IConsumer<TestDTO>
{
    private readonly ITestService _service;
    public TestConsumer(ITestService service)
    {
        _service = service;
    }
 
    public async Task Consume(ConsumeContext<TestDTO> context)
    {
        var randomNumbers = _service.GetRangedNumbers(context.Message.Limit);
 
        await context.RespondAsync(new TestResponse
        {
            Data = randomNumbers,
        });
    }
}
				
			

Step 9: This TestController is an API controller responsible for handling HTTP GET requests. It uses the Mediator pattern via the injected IMediator instance to handle the request. The GetRandomNumbers action method receives a query parameter TestDTO from the request, which contains a Limit property.

It then creates a request client using the Mediator to send a request to the appropriate consumer. Finally, it returns the response received from the consumer as an HTTP OK result.

				
					[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    private readonly IMediator _mediator;
 
    public TestController(IMediator mediator)
    {
        _mediator = mediator;
    }
 
    [HttpGet]
    public async Task<IActionResult> GetRandomNumbers([FromQuery] TestDTO query)
    {
        var response = await _mediator.CreateRequestClient<TestDTO>()
                        .GetResponse<TestResponse>(new TestDTO
                        {
                            Limit = query.Limit,
                        });
 
        return Ok(response.Message);
    }
 
}
				
			

Step 10: Now, open the browser and test the endpoint to see if it’s being hit or not.

Test the endpoint to see if it's being hit or not

Our API is functioning properly. Now, let’s proceed to test the consumer. Initially, we need to create a separate project for unit testing. We’ll also establish a unit test project using NUnit. Follow some steps for better understanding.

Step 1: Create a Unit Test Project in the same solution as MasstransitConsumer.

Create a Unit Test Project in the same solution as MasstransitConsumer

Step 2: Find NUnit.

Find NUnit in the Unit Test Project

Step 3: Give a name.

Give a name to the Unit Test project

Now, take a look at the created project. We need to install some necessary NuGet packages.

Check the project to install some NuGet packages

Step 4: Follow packages you have to install.

Follow packages you have to install

Step 5: Include the API project in the unit test project as a shared project reference.

Include the API project as a shared project reference

Step 6: Now select the project.

Now select the project in MasstransitConsumer unit test

Step 7: Now, adjust the UnitTest class that has already been created. If it hasn’t been generated automatically, you’ll need to create a class named UnitTest as an example. Also add annotation [ExcludeFromCodeCoverage]

				
					[ExcludeFromCodeCoverage]
public class UnitTest
{
    private readonly ITestService testServiceMoq;
    public UnitTest()
    {
        testServiceMoq = Substitute.For<ITestService>();
    }
}
				
			

Step 8: We’ll adhere to a straightforward rule for Unit Testing.

Arrange : This entails arranging or setting up the required parameters for the test.
Act: This involves simply executing the action, such as calling a method or invoking a controller.
Assert: Means just evaluate the result.

Now, There is a unit test method written using NUnit for testing the functionality of the GetRandomNumbers action method in the TestController. Here’s a brief explanation of each section:

1. Arrange:

  • Set up the test scenario by defining the limit for generating random numbers

  • Create a range of numbers from 0 to the specified limit

  • Configure the behavior of the mocked ITestService instance (testServiceMoq) to return the generated numbers when called with the specified limit

  • Set up the Masstransit test harness and add the TestConsumer as a consumer

2. Act:

  • Perform the action being tested, which is sending a request to the controller’s GetRandomNumbers action method using the Masstransit test harness

3. Assert:

  • Verify that the response received from the controller is not null

  • Ensure that the data in the response message has the expected count, which should match the specified limit

4. Cleanup:

  • Stop the Masstransit test harness

  • Dispose of the service provider after the test execution
				
					[Test]
public async Task Get_Random_Numbers_Should_Return_List()
{
    //////////Arrange
 
    int limit = 100;
 
    var numbers = Enumerable.Range(0, limit);
 
    testServiceMoq.GetRangedNumbers(limit).Returns(numbers);
 
    //Configure masstransit consumer with masstransit harness
 
    await using var provider = new ServiceCollection()
        .AddScoped(provider => testServiceMoq)
        .AddMassTransitTestHarness(opt =>
        {
            opt.AddConsumer<TestConsumer>();
        })
        .BuildServiceProvider(true);
 
    //Register the Test service
    var harness = provider.GetRequiredService<ITestHarness>();
 
    await harness.Start();
 
    //Request with Test DTO
    var client = harness.GetRequestClient<TestDTO>();
 
    ////////////Act
 
    //Response 
    var response = await client.GetResponse<TestResponse>(new TestDTO
    {
        Limit = limit
    });
 
    ///////////Assert
    response.Message.Should().NotBeNull();
    response.Message.Data.Should().HaveCount(limit);
 
    await harness.Stop();
    await provider.DisposeAsync();
}
				
			

Step 9: Our test code is in good shape. Now, we need to set up code coverage tools. For educational purposes, we’ll utilize a free tool called Fine Code Coverage, which is available as a Visual Studio extension manager. Look for Fine Code Coverage in the extensions.

In my case, the extension is already installed. If you haven’t installed it yet, you’ll need to do so first. After the installation is finished, restart Visual Studio. Then, the extension should work properly.

Install Fine Code Coverage in Visual Studio code manager

Step 10: To run the test method, navigate to Test -> Test Explorer.

Screenshot of To run the test method navigate to Test then Test Explorer

Step 11: Have a look at Test Explorer. Follow the red arrow or you can right click the method name and click test option.

Screenshot of click method name and test option in Test Explorer

Step 12: Now, take a look to see if the test code has passed. If it hasn’t, review your code and address any errors indicated.

Screenshot of Now check the test code to see if it has passed

Step 13: Let’s open the code coverage to examine how your code was tested. Navigate to View -> Other Windows -> See Fine Code Coverage. This is the extension you installed earlier.

Screenshot of open the code coverage to examine

Step 14: Review the code coverage results after testing the method.

Screenshot of Review the code coverage results after testing

Conclusion

This article hasn’t encompassed every aspect of professional unit testing with Masstransit mediator. While working with microservices, there may arise a need for these techniques, but here you’ve gained familiarity with some fundamental concepts.

There exist several guidelines and best practices to aim for when crafting unit tests and achieving code coverage. Adhering to these practices will undoubtedly simplify your work (and that of your fellow developers).

Potential Developer
Tech Stack
0 +
Accelerate Your Software Development Potential with Us
With our innovative solutions and dedicated expertise, success is a guaranteed outcome. Let's accelerate together towards your goals and beyond.
Blogs You May Love

Don’t let understaffing hold you back. Maximize your team’s performance and reach your business goals with the best IT Staff Augmentation