Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Autofixture tests intermittently fail when using NCrunch
royboy23
#1 Posted : Thursday, September 29, 2016 6:25:36 AM(UTC)
Rank: Member

Groups: Registered
Joined: 3/3/2014(UTC)
Posts: 21
Location: Germany

Thanks: 3 times
Hi,

I'm using NCrunch (latest version) to run a few hundred unit tests implemented with NUnit 3, Autofixture and the Autodata / AutoMoqData attributes. My tests always pass when running them sequentially, but when parallelizing them sometimes I get some random errors that seem to be related to multi-threading.

For instance this just failed once:

Code:
 [Theory]
        [AutoMoqData]
        public async Task DownloadAddsAllNewEntitiesToRepository(
            [Frozen] IApiCollectionProxy<Project> proxy,
            [Frozen] IEntityService<Project> entityService,
            List<Project> input,
            ProjectsSyncManager sut)
        {
            //Setup
            var lastSyncTime = input.Min(e => e.LastChangeTime);
            var proxyMock = Mock.Get(proxy);
            var cancellationToken = CancellationToken.None;

            proxyMock.Setup(p => p.LoadAllAsync(It.IsAny<Expression<Func<Project, bool>>>(), cancellationToken))
                .Returns((Expression<Func<Project, bool>> exp, CancellationToken can) => Task.FromResult(input.Where(exp.Compile())));

            Mock.Get(entityService).Setup(s => s.Exists(It.IsAny<int>())).Returns(false);

            Mock.Get(entityService).Setup(s => s.FindDuplicate(It.IsAny<Project>()))
                .Returns((Project p)=>null);

            //Execution
            await sut.DownloadAsync(2, lastSyncTime, cancellationToken);
            //Assertion

            //ASSERTION IN NEXT LINE FAILED: Expected invocation on the mock exactly 3 times, but was 6 times: s => s.Add(It.IsAny<Project>())
            Mock.Get(entityService).Verify(s => s.Add(It.IsAny<Project>()), Times.Exactly(input.Count()));
        }


In this case it seems that the same mock is used in two different unit tests at once. If I re-run the test it does not fail. Errors like these are quite rare, but all over the place in my test suite.

Now I am not even sure which technology I am using here is at fault. Is this an NCrunch problem, an NUnit Problem, an Autofixture problem?

And is there any workaround (Short of running everything in isolation or sequentially)?

Thanks,

Adrian
Remco
#2 Posted : Thursday, September 29, 2016 9:55:46 AM(UTC)
Rank: NCrunch Developer

Groups: Administrators
Joined: 4/16/2011(UTC)
Posts: 7,145

Thanks: 959 times
Was thanked: 1290 time(s) in 1196 post(s)
Hi Adrian,

Thanks for sharing this problem!

NCrunch won't run tests concurrently within the same process, but with parallel execution enabled it can run them in parallel across multiple processes. This means that if your code under test is interacting with something outside the test process, there is the potential for race conditions.

See here for more information about parallel execution - http://www.ncrunch.net/documentation/considerations-and-constraints_concurrent-use-of-test-resources.

It's very important that any tests with multi-threaded behaviour ensure that all spawned threads have completed their execution before the test itself completes. See http://www.ncrunch.net/documentation/considerations-and-constraints_multi-threaded-tests.

Very often, tests can exhibit state or sequence related issues when run with NCrunch if they have not been designed for variable execution order. These issues can look very much like multi-threading issues. See http://www.ncrunch.net/documentation/considerations-and-constraints_test-atomicity.
royboy23
#3 Posted : Thursday, September 29, 2016 10:47:49 AM(UTC)
Rank: Member

Groups: Registered
Joined: 3/3/2014(UTC)
Posts: 21
Location: Germany

Thanks: 3 times
Hi Remco,

thanks about your quick reply. I am aware of the issues you have mentioned since I have been using NCrunch for several years now and mitigated similar problems with a quite large test suite containing many unit and integration tests.

However, I have previously only been using NUNit V2 and some (limited) Ninject DI and did everything else (DI, Mocking, Faking, Test fixture setup, ...) in my own source code. So while there were plenty of issues with multithreaded tests, I knew what was going on and was able to make everything thread-safe so that no more problems occured.

However, this time I using 100% unit tests with all dependencies as mocks. Mocks are (transparently) created by Autofixture for each test alone. I have double-checked that there are no common resources shared by any tests in my source code, so theoretically there should not be any problem. However, the problems are still here, so there must be some issue.

As you can see in my code snippet, there is a lot of 3rd party code "black magic" going on behind the scenes for dependency mocking and fixture creation. So I can't just look at the source code or fire up the debugger to see what is going on quite as easily.

Now I don't know where to look next. This could be an NCrunch, an NUnit, Autofixture or (though unlikely) even a Moq problem. Or it could be a combination of these. I was wondering if you have any idea how to proceed here.
Remco
#4 Posted : Thursday, September 29, 2016 9:48:42 PM(UTC)
Rank: NCrunch Developer

Groups: Administrators
Joined: 4/16/2011(UTC)
Posts: 7,145

Thanks: 959 times
Was thanked: 1290 time(s) in 1196 post(s)
royboy23;9230 wrote:

Now I don't know where to look next. This could be an NCrunch, an NUnit, Autofixture or (though unlikely) even a Moq problem. Or it could be a combination of these. I was wondering if you have any idea how to proceed here.


Sorry. Unless you're able to provide me with a self-contained code sample that can consistently produce a threading issue in NCrunch, all I can really do is try to give targeted advise on the normal sorts of problems encountered by people that may cause erratic behaviour in testing.

Marking tests with the [Isolated] attribute will allow them to run in isolation and may mask the problem, but this isn't an effective long term solution as it will significantly slow the execution of your tests.

Something you could try is placing intermittent Debug.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId.ToString()) calls throughout the code being executed, as this might give some indication of how the code is being run on background threads. It may be that you have a test further up in the suite that is kicking something off and is interfering with the execution of tests run later in the suite.
Users browsing this topic
Guest
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

YAF | YAF © 2003-2011, Yet Another Forum.NET
This page was generated in 0.037 seconds.
Trial NCrunch
Take NCrunch for a spin
Do your fingers a favour and supercharge your testing workflow
Free Download