Daily Usage Issues

Problems with automapper?

Started by SteveCooperOrg on 9,708 views

Hi,

Anyone got any experience with running NCrunch on a project with lots of calls to AutoMapper? We have lots of fixtures that need AutoMapper to have been initialized -- something like

AutoMapperConfig.Initialize(configForATest);


or

AutoMapperConfig.Initialize(configForAnotherTest);


Now, AutoMapper is basically a big global object, re-configured every time you call .Initialize(). Although I've tried to make my tests run serially, some tests fail on a first pass because they trip up with other tests; However, I can get all the tests to pass by repeatedly clicking 'Run all visible tests here' -- every time, a few more pass, until they all pass.

This doesn't occur in the Visual Studio Test Explorer window.

I've set these variables which I'd hope would have made my tests totally serial, but it doesn't seem to help;


    General Settings.CPU cores assigned to NCrunch: 0
    General Settings.Max number of processing threads: 1
    General Settings.Max number of test runner processes to pool: 1


Anyone suggest anything to get NCrunch and AutoMapper to play nicely with each other?

Steve

PS: Failures generally look like this;

NCrunch: This test was executed on server '(local)'

AutoMapperConfig - Creating mappings
An exception was thrown in the Task Environment: AutoMapper.AutoMapperMappingException: 

Mapping types:
XXXXXXXXXXX -> ICollection`1
XXXXXXXXXXX.XXXXXXXXXXX.XXXXXXXXXXX -> System.Collections.Generic.ICollection`1[[XXXXXXXXXXX.XXXXXXXXXXX.XXXXXXXXXXX.XXXXXXXXXXX, XXXXXXXXXXX.XXXXXXXXXXX, Version=1.66.5679.15956, Culture=neutral, PublicKeyToken=null]]

Destination path:
XXXXXXXXXXX.XXXXXXXXXXX.XXXXXXXXXXX

Source value:
XXXXXXXXXXX.XXXXXXXXXXX.XXXXXXXXXXX ---> System.ArgumentNullException: Cannot be null
Parameter name: root
   at Ninject.ResolutionExtensions.GetResolutionIterator(IResolutionRoot root, Type service, Func`2 constraint, IEnumerable`1 parameters, Boolean isOptional, Boolean isUnique)
   at Ninject.ResolutionExtensions.Get(IResolutionRoot root, Type service, IParameter[] parameters)
   at XXXXXXXXXXX.App_Start.AutoMapperConfig.<>c__DisplayClass5.<CreateMappingsWithInjection>b__1(Type type) in XXXXXXXXXXX\App_Start\AutoMapperConfig.cs:line 65
   at AutoMapper.MappingExpression`2.<>c__DisplayClass3a`1.<BuildCtor>b__39(ResolutionContext context) in c:\dev\AutoMapper\src\AutoMapper\Internal\MappingExpression.cs:line 554
   at AutoMapper.DeferredInstantiatedResolver.Resolve(ResolutionResult source) in c:\dev\AutoMapper\src\AutoMapper\Internal\DeferredInstantiatedResolver.cs:line 16
   at AutoMapper.PropertyMap.<ResolveValue>b__6(ResolutionResult current, IValueResolver resolver) in c:\dev\AutoMapper\src\AutoMapper\PropertyMap.cs:line 127
   ...
A follow-up -- I've applied

NCrunch.Framework.SerialAttribute


to all my test projects, but the documentation at https://www.ncrunch.net/documentation/reference_runtime-framework_serial-attribute seems to suggest that this will only ensure serial execution within each assembly;


This attribute can be applied at assembly level, in which case all tests within the assembly will be run without parallel execution.


Is that interpretation right? Will the serial attribute not ensure that tests in different test assemblies run independently?
Hi Steve,

Unfortunately, there isn't an NCrunch setting that will adequately fix this problem. This is because of the way in which NCrunch breaks your tests up into batches and calls into the test runner process multiple times (once for each batch). This is needed to allow the engine to drive test frameworks to execute tests in a dynamic order, which is required for continuous testing.

How are you currently initialising your automapper config? Is this being done in a SetUpFixture? A simple fix would be to introduce a static boolean flag check around the method call, for example:

private static bool autoMapperInitialised = false;

public void InitialiseTestEnvironment()
{
if (autoMapperInitialised == false)
{
AutoMapperConfig.Initialize(configForATest);
autoMapperInitialised = true;
}
}

This page gives some more details and is worth having a read of - http://www.ncrunch.net/documentation/considerations-and-constraints_test-atomicity.

Also, if you set this setting to 1, it will likely solve your problem ... but the engine will perform very poorly: http://www.ncrunch.net/documentation/reference_global-configuration_test-process-memory-limit.
I use AutoMapper throughout my projects, and ncrunch doesn't have a problem with it.

I'm not sure what your AutoMapperConfig method is, but I define all my mappings in Profile objects, and just call Mapper.AddProfile<RelevantProfile>() in the TestInitialize or Setup method of a test fixture. I've also been successful doing this in the Assembly Initialise method in order to reduce the number of setups required.

I also unit test each automapper profile independently with an assertion method which uses a private automapper instance.

If you dislike the global automapper approach, you could always inject a mapping engine into your code - your test fixtures would then be able to guarantee it has been correctly initialised.
rlawley - my automapper is more complicated than the usual case because I'm using Ninject when constructing various Resolvers. This means that AutoMapper is stateful for each test. It's a bit of an unholy place to be but so long as I can do;

Mapper.Reset()
Mapper.Map<Stuff, StuffDto>()

at the start of a fixture, and have each fixture run independently, I think it'll work. But that looks tricky,

Post a reply

Log in to reply.