Hi guys,
I have a problem. First time when i run unit test for a project most tests failed because AutoMapper.AutoMapperMappingException: AutoMapper.AutoMapperMappingException : Missing type map configuration or unsupported mapping.
I have all profilers to map all necessary type. When i run these tests for second time - everything is good.
Could you help me with identifing the problem?
Thanks in advance.
What test runner are you using?
On Tue, Feb 18, 2014 at 3:15 AM, Victor Bilokin [email protected]:
Hi guys,
I have a problem. First time when i run unit test for a project most tests
failed because AutoMapper.AutoMapperMappingException:
AutoMapper.AutoMapperMappingException : Missing type map configuration or
unsupported mapping.I have all profilers to map all necessary type. When i run these tests for
second time - everything is good.Could you help me with identifing the problem?
Thanks in advance.
Reply to this email directly or view it on GitHubhttps://github.com/AutoMapper/AutoMapper/issues/463
.
xUnit 1.4 or Ncrunch 1.48 Does it really matter?
Just trying to get all the info so that I can reproduce, I've never seen anything like this before. Especially running tests once vs. twice - both of those tools isolate runs in AppDomains. Are you making sure your configuration is called before any test is run? In xUnit you can do this with a static ctor and Lazy
public class BaseAutoSubstituteTest
{
private static object isInitialized=false;
static BaseAutoSubstituteTest()
{
lock (isInitialized)
{
if ((bool) isInitialized) return;
SetupAutoMapper();
isInitialized = true;
}
}
public AutoSubstitute Mocks { get; set; }
public BaseAutoSubstituteTest()
{
Mocks = new AutoSubstitute();
DependencyResolver.SetResolver(new AutofacDependencyResolver(Mocks.Container));
ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(Mocks.Container));
}
static Assembly[] assemblies = {
Assembly.Load("Admin.Service"),
Assembly.Load("Policy.Service"),
Assembly.Load("SystemData.Service"),
Assembly.Load("Providers"),
Assembly.Load("Infrastructure")
};
public static void SetupAutoMapper()
{
Mapper.Reset();
Mapper.Initialize(cfg =>
{
foreach (var assembly in assemblies)
{
var profiles = (assembly.GetTypes())
.Where(t => (t.IsSubclassOf(typeof(Profile)) && t.GetConstructor(Type.EmptyTypes) != null))
.Select(p => (Profile)Activator.CreateInstance(p));
foreach (var item in profiles)
{
cfg.AddProfile(item);
}
}
cfg.AllowNullDestinationValues = true;
});
}
}
This is sample of usual base class for all tests. So, static ctor that call static automapper initializer allow do initialization only 1 time. I have no construction with locking object, but add it ( because thought it could be a problem with multi threading). But lock does not help.
What you can suggest?
Thanks! Well, everything looks OK, I'll try to create a repro on my side.
In the meantime, you can try debugging or outputting diagnostic information
to make sure your setup is getting called on that first run.
On Tue, Feb 18, 2014 at 8:18 AM, Victor Bilokin [email protected]:
public class BaseAutoSubstituteTest
{
private static object isInitialized=false;static BaseAutoSubstituteTest() { lock (isInitialized) { if ((bool) isInitialized) return; SetupAutoMapper(); isInitialized = true; } } public AutoSubstitute Mocks { get; set; } public BaseAutoSubstituteTest() { Mocks = new AutoSubstitute(); DependencyResolver.SetResolver(new AutofacDependencyResolver(Mocks.Container)); ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(Mocks.Container)); Mocks.Provide<ITypeAdapter>(new AutomapperTypeAdapter()); Fixture = new Fixture(); Fixture.ApplyDefaultCustomization(); Fixture.RepeatCount = 1; //add more customization to your test constructor, if needed MockCompanyIdentity(); } static Assembly[] assemblies = { Assembly.Load("Admin.Service"), Assembly.Load("Policy.Service"), Assembly.Load("SystemData.Service"), Assembly.Load("Providers"), Assembly.Load("Infrastructure") }; public static void SetupAutoMapper() { Mapper.Reset(); Mapper.Initialize(cfg => { foreach (var assembly in assemblies) { var profiles = (assembly.GetTypes()) .Where(t => (t.IsSubclassOf(typeof(Profile)) && t.GetConstructor(Type.EmptyTypes) != null)) .Select(p => (Profile)Activator.CreateInstance(p)); foreach (var item in profiles) { cfg.AddProfile(item); } } cfg.AllowNullDestinationValues = true; }); }}
This is sample of usual base class for all tests. So, static ctor that
call static automapper initializer allow do initialization only 1 time. I
have no construction with locking object, but add it ( because thought it
could be a problem with multi threading). But lock does not help.What you can suggest?
Reply to this email directly or view it on GitHubhttps://github.com/AutoMapper/AutoMapper/issues/463#issuecomment-35387822
.
Can't reproduce :(
It might be that the issue exists but it's very elusive.
I'm on XUnit 2.1.0 and Automapper 4.0.4. Using Resharper runner.
Just run into "sounds similar" issue:
Unit testing WebAPI controllers and because my mapper profile was loaded inside autofac configuration - to properly setup controller SUTs I had to run automapper initialization in unit test class ctor like this:
AutoMapper.Mapper.Reset();
AutoMapper.Mapper.Initialize(cfg => {cfg.AddProfile<AutoMapperProfile>();});
AutoMapper.Mapper.AssertConfigurationIsValid();
Initially I was running it in non-static ctor and when I have to run multiple unit tests in parallel ( about 50) - I got flux of few tests failing randomly with same error message. When ran 1 by 1 - they always green. It looks like race condition and appears once per 3-5-7 successful-all-green runs. Very ocassionally
Follow up investigation discovered:
Cool, now all tests for a single controller are always green. Except when they being ran in a batch with other controller tests - it fails even more seldom, but still.
It feels that there is a potential very rare race condition around AutoMapper.Mapper.Reset(); when it's called often (in non-static ctor = for each test, in static ctor - once per class initialization).
Commenting this line out and moving test setup into static ctor for each test made my test results "always green" within 20 consequent runs. But I still suspect that it's because my initialization is now in static ctor and not in object ctor.
One thing - Mapper.Initialize calls Mapper.Reset - so that's redundant.
This is a good point. Do you still think it's worth to chase and repro the race condition in mapper static calls or its unlikely there?
I had a similar issue as described here and found that I had other tests calling Initialize outside of my one centralized base class for Automapper profile tests. Once I changed them to all use the same thread safe static constructor (similar to @Ciget) that loads all profiles needed across all tests, my issues went away.
Taking into account what @jbogard said, the parallelism of the xunit runner seemed to be causing the outlying Mapper.Initialize calls to most likely call Reset on the Mapper and stomp on the configuration of other tests and cause them to fail.
@centur, have you looked at how many different Mapper.Initialize calls are being called across all of your tests in one of your batches? You may want to check and see if have some random outliers that may be stomping on your tests when the parallelism of the test runner executes them.
@jmurret I have one in each static constructor of the test class which now feels fine - working without issues, but this just rings the bell for me that Initialize method is not a thread-safe one.
I also came across this issue in a DNX ASP.NET 5 test project. I'm providing my solution here for posterity--perhaps it'll help someone else.
I moved the call to Initialize(cfg => { cfg.CreateMap... to static constructors and my tests ran slightly more reliably, but still not completely consistently. I ended up setting up my configuration class like so:
public class MapperConfiguration
{
public static void Configure()
{
Mapper.Initialize(cfg =>
{
cfg.AddProfile<ApiModelProfile>();
});
}
public static void ConfigureForTests()
{
Mapper.AddProfile<ApiModelProfile>();
}
public class ApiModelProfile : Profile
{
protected override void Configure()
{
this.CreateMap<Order, OrderDto>();
}
}
}
And then called MapperConfiguration.ConfigureForTests() in static constructors. (Well, actually, I got it to work reliably enough that I put it in an AutomapFixture class and implemented IClassFixture<AutomapFixture> on all classes that I had previously been using static constructors.)
Note that I'm also using the IgnoreAllNonExisiting extension described here: AutoMapper: "Ignore the rest"? which may have been contributing to the issue though didn't have a good way to test.
I am experiencing the same problem and it is very annoying. When I run all tests, one of them fails. When I run that same test by itself, it works. Please help! My Repo:
https://github.com/PivotalAnimal/BlueConcord.IdentityServer.EntityFrameworkCore
This issue happens for me too. Would there be a way to instantiate a Mapper without having its configuration be stored statically? That way, each unit test can create its own instance.
Turns out that's actually possible - instantiating my own mapper per unit test works like a charm.
@sfmskywalker Could you elaborate a little bit more? Do you instantiate a mapper instance per test and inject it into your system under test?
@VinS101 That's exactly right. For example, this is what I do in the constructor of my xUnit tests:
public class MyServiceTests
{
private readonly IMapper _mapper;
public MyServiceTests()
{
_mapper = new MapperConfiguration(cfg => cfg.AddProfile<MyMappingProfile>()).CreateMapper();
}
}
This will cause a new mapper instance to be created for each individual test.
Thanks for your clarification, @sfmskywalker. Seems like the dependency on Automapper is loosely coupled in your codebase. In my case, my codebase has a dependency on the static Automapper, (which is obviously not good).
Currently, I am configuring the Automapper in a lock statement for every test fixture. However, the deadlocks still happen from time to time.
Correct @VinS101 , I basically inject IMapper via constructors of the classes that require mapping, and configured DI as follows:
services
.AddAutoMapper()
.AddAutoMapperProfile<MyMappingProfile>()
The above two extension methods are my own implementations, as follows:
using System;
using AutoMapper;
using Microsoft.Extensions.DependencyInjection;
namespace AutoMapper.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddAutoMapper(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
services.AddSingleton(CreateConfigurationProvider);
services.Add(new ServiceDescriptor(typeof(IMapper), sp => new Mapper(sp.GetRequiredService<IConfigurationProvider>(), sp.GetService), lifetime));
return services;
}
public static IServiceCollection AddAutoMapperProfile<TProfile>(this IServiceCollection services)
where TProfile : Profile
{
return services.AddTransient<Profile, TProfile>();
}
private static IConfigurationProvider CreateConfigurationProvider(IServiceProvider serviceProvider)
{
var profiles = serviceProvider.GetServices<Profile>();
var configuration = new MapperConfiguration(x =>
{
foreach (var profile in profiles)
{
x.AddProfile(profile);
}
});
return configuration;
}
}
}
As you can see, this enables you to choose what lifetime scope you want to use for IMapper, be it Singleton or Scoped.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Turns out that's actually possible - instantiating my own mapper per unit test works like a charm.