0

I am using ASP.NET Boilerplate template for ASP.NET Core. I have some application services which I have successfully unit tested.

I now want to test a controller method which uses these application services. The controller method includes mapping operation like this:

var client = ObjectMapper.Map<ClientModel>(clientResponse.ClientSummary);

On executing this method, the test fails with an exception:

Message: Abp.AbpException : Abp.ObjectMapping.IObjectMapper should be implemented in order to map objects.

Interestingly, the stack trace begins with NullObjectMapper.Map.

I am using the same initialisation for AbpAutoMapper in the unit test module as is used in the Web.Mvc module:

Configuration.Modules.AbpAutoMapper().Configurators.Add(cfg =>
{
    cfg.AddProfiles(typeof(PortalTestModule).GetAssembly());
});

However, when executing in the context of the MVC application, the mapping operations don't cause the exception.

What is it that I am failing to initialise in the Test project in relation to AutoMapper?


I have created a repro project. See link. There is a test called GetFoos_Test that tests the controller method Index() on FoosController.

public async Task GetFoos_Test()
{
    var mockFooService = new Mock<IFooAppService>();
    // ...

    var fooController = new FooController(mockFooService.Object);

    var result = await fooController.Index();

    result.ShouldNotBeNull();
}

As per @aaron's answer, property injecting IObjectMapper on the controller does solve the original error. However, it doesn't use the mappings that are part of what I am trying to test. I have created mappings in the Initialize method of the MVC module like this:

public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(MyMvcModule).GetAssembly());

            Configuration.Modules.AbpAutoMapper().Configurators.Add(
               // Scan the assembly for classes which inherit from AutoMapper.Profile
               cfg =>
               {
                   cfg.AddProfiles(typeof(MyMvcModule).GetAssembly());

                   cfg.CreateMap<MyDto, MyModel>()
                       .ForMember(dest => dest.ReportTypeName, src => src.MapFrom(x => x.ReportType.Name));
... 

Conor McCarthy
  • 232
  • 3
  • 12

1 Answers1

1

1. NullObjectMapper in new instances

IObjectMapper is property-injected into an instance (e.g. controller) when the instance is injected.

Since you cannot inject a controller in a unit test, you have to set ObjectMapper directly.

// using Abp.ObjectMapping;

var fooController = new FooController(mockFooService.Object);
fooController.ObjectMapper = LocalIocManager.Resolve<IObjectMapper>(); // Add this line

2. NullObjectMapper in injected instances

Add [DependsOn(typeof(AbpAutoMapperModule))] to your test module.

[DependsOn(typeof(AbpAutoMapperModule))]
public class MyTestModule : AbpModule
{
    // ...
}
aaron
  • 39,695
  • 6
  • 46
  • 102
  • Thanks, I tried this but the result is exactly the same. – Conor McCarthy Apr 16 '19 at 06:19
  • Create a repro project on GitHub that is forked from [aspnetboilerplate/module-zero-core-template](https://github.com/aspnetboilerplate/module-zero-core-template). – aaron Apr 16 '19 at 10:22
  • I have created a repro project. See [link](https://github.com/muiscatron/module-zero-core-template). There is a test called GetFoos_Test which tests the controller method Index() on FoosController. The controller method is wired up so that it works in the UI. – Conor McCarthy May 10 '19 at 08:11
  • Have you had a chance to look at this project? – Conor McCarthy May 30 '19 at 09:20
  • Apologies for the long delay. The original problem is resolved, i.e. IObjectMapper is now available. However, part of what I was trying to test was the object mappings in my MVC project. I had defined these in the Initialize method of the MVC application module, but when the tests execute, they are using an "empty" object mapper. See edited question – Conor McCarthy Aug 12 '19 at 14:27