While running some of my tests today, I suddenly got an IndexOutOfRangeException
, with the following stack trace:
at System.Collections.Generic.List`1.Add(T item) |
The code under test was using Tasks to do some work in the background, and was using a fake instance of an ILogger
, which was created with FakeItEasy and passed to the code under test.
The above stack trace shows a classic symptom of a thread-safety issue. Searching for this issue led me to this bug report, where a similar problem was described. Patrik Hägne, the creator of FakeItEasy, argues that using threading in tests is always problematic, however provides a nice and elegant solution to work around the problem.
The problem, of course, that the fake instance of the logger was not thread-safe, causing the underlying interceptor to incorrectly record the calls made to the fake logger object. However, when creating fake objects with FakeItEasy, it’s possible to specify build options for the fake instance. This is where Patrik’s solution comes in: wrap the fake instance with a syncronization interceptor, which can be applied in the following way:
A.Fake<ILogger>(x => x.Synchronized()); |
Where Synchronized()
is an extension method you can define in your tests:
public static class MyPersonalFakeExtensions |
And CallSynchronizer
is an implementation of IInterceptionListener
, which simply adds locking around method execution:
public class CallSynchronizer : IInterceptionListener |
And that’s it - using this code you can create a thread-safe fake objects to use in your tests, if you require.