Home > Mobile >  Unittesting a ServiceStack service that uses AutoMapper
Unittesting a ServiceStack service that uses AutoMapper

Time:02-02

We are using ServiceStack for our .NET backend and I am trying to work on getting unit testing into the project. However there are some automated tools within ServiceStack that makes it a bit complicated to isolate the units so I could really use some advice. In the example below I would like to unit test a simple service that basically does the following:

  1. Takes a request DTO
  2. Passes the DTO to the repository
  3. Gets back a domain model
  4. If the model exists, it maps it to a responseDTO using Automapper and returns it as a part of an IHTTPResult

So the problem I have is that it seems like Automapper is automatically added to the ServiceStack application and in the application the mapper are registered by just calling:

AutoMapping.RegisterConverter().

So how could I inject this into the service to be able to do the unittest?

Example test:

using AutoMapper;
using FluentAssertions;
using NSubstitute;

namespace Api.Services.Tests.Unit;

public class OrderApiServiceTests
{
    private readonly OrderApiService _sut;
    private readonly IOrderApiRepository accountApiRepository = Substitute.For<IOrderApiRepository>();

    public OrderApiServiceTests()
    {
        _sut = new OrderApiRepository(orderApiRepository);
        var config = new MapperConfiguration(cfg => ApiDtoMapping.Register());
        var mapper = config.CreateMapper();
    }

    [Fact]
    public async Task Get_ShouldReturnAccount_WhenAccountExistsAsync()
    {
        // Arrange
        var order = new Order
        {
            Name = "MyOrder",
            Value = 1000,
        };

        var expectedResponse = new OrderApiDto
        {
            Name = "MyOrder",
            Value = 1000,
        };

        orderApiRepository.GetAsync(Arg.Any<GetOrder>()).Returns(order);

        // Act
        var result = await _sut.Get(new GetOrder());

        // Assert
        result.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
        result.Response.Should().BeEquivalentTo(expectedResponse);
    }
}

Added a full example including all files:

// Program.cs
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
    app.UseHttpsRedirection();
}

app.UseServiceStack(new AppHost());
app.Run();

// Configure.AppHost.cs
using Funq;
using ssUnitTests.ServiceInterface;

[assembly: HostingStartup(typeof(ssUnitTests.AppHost))]

namespace ssUnitTests;

public class AppHost : AppHostBase, IHostingStartup
{
    public void Configure(IWebHostBuilder builder) => builder
        .ConfigureServices(services =>
        {
        });

    public AppHost() : base("ssUnitTests", typeof(MyServices).Assembly) { }

    public override void Configure(Container container)
    {
        container.RegisterAutoWiredAs<OrderRepository, IOrderRepository>().ReusedWithin(ReuseScope.None);

        // Configure ServiceStack only IOC, Config & Plugins
        SetConfig(new HostConfig
        {
            UseSameSiteCookies = true,
        });

        Mappings.RegisterConverters();
    }
}

// Mappings.cs
using ssUnitTests.ServiceModel;

namespace ssUnitTests;

public static class Mappings
{
    public static void RegisterConverters()
    {
        AutoMapping.RegisterConverter((Order from) =>
        {
            var to = from.ConvertTo<OrderDto>();
            to.DtoProperty = from.BaseProperty   "Dto";
            return to;
        });
    }
}

// IOrderRepository.cs
using ssUnitTests.ServiceModel;

namespace ssUnitTests.ServiceInterface;

public interface IOrderRepository
{
    Order GetOrder();
}

// Order.cs
namespace ssUnitTests.ServiceModel;

public class Order
{
    public string Name { get; set; }
    public string BaseProperty { get; set; }
}

// OrderDto.cs
namespace ssUnitTests.ServiceModel;

public class OrderDto
{
    public string Name { get; set; }
    public string DtoProperty { get; set; }
}

// OrderRequest.cs
using ServiceStack;

namespace ssUnitTests.ServiceModel;

[Route("/order")]
public class OrderRequest : IReturn<OrderDto>
{
    public int Id { get; set; }
}

// UnitTest.cs
using NSubstitute;
using NUnit.Framework;
using ssUnitTests.ServiceInterface;
using ssUnitTests.ServiceModel;

namespace ssUnitTests.Tests;

public class UnitTest
{
    private readonly MyServices _sut;
    private readonly IOrderRepository _repository = Substitute.For<IOrderRepository>();

    public UnitTest()
    {
        _sut = new MyServices(_repository);
    }

    [Test]
    public void Get_ShouldReturn_OrderDto()
    {
        var order = new Order
        {
            Name = "MyName",
            BaseProperty = "MyBaseProperty"
        };

        _repository.GetOrder().Returns(order);

        var response = (OrderDto)_sut.Any(new OrderRequest { Id = 1 });

        Assert.That(response.Name.Equals(order.Name));
        Assert.That(response.DtoProperty.Equals(order.BaseProperty   "Dto"));
    }
}

CodePudding user response:

ServiceStack.dll does not have any dependencies to any 3rd Party Libraries, e.g. it's built-in AutoMapping is a completely different stand-alone implementation to AutoMapper.

If you're using AutoMapper you can ignore ServiceStack's AutoMapping which is completely unrelated.

  • Related