Unit tests that use FakeItEasy randomly fail when trying to fake a simple intefrace. It occurs in different tests occasionally and is not stable.
Here is a sample interface I need to fake:
public interface IJobSuiteFilterApplier
{
JobSuiteDto FilterJobSuites(JobSuiteDto jobSuiteDto, JobSuiteFilter jobSuiteFilter);
}
Here is piece of code that creates the fake and fails sometimes:
var jobSuiteFilterApplier = A.Fake<IJobSuiteFilterApplier>(x => x.Strict());
Here is the exception details:
FakeItEasy.Core.FakeCreationException:
Failed to create fake of type "QS.TestShell.Server.ExecutionPlanner.Queries.IExecutionPlannerQueryService".
Below is a list of reasons for failure per attempted constructor:
No constructor arguments failed:
No usable default constructor was found on the type QS.TestShell.Server.ExecutionPlanner.Queries.IExecutionPlannerQueryService.
An exception was caught during this call. Its message was:
Collection was modified; enumeration operation may not execute.
at FakeItEasy.Core.DefaultExceptionThrower.ThrowFailedToGenerateProxyWithResolvedConstructors(Type typeOfFake, String reasonForFailureOfUnspecifiedConstructor, IEnumerable`1 resolvedConstructors)
at FakeItEasy.Creation.FakeObjectCreator.TryCreateFakeWithDummyArgumentsForConstructor(Type typeOfFake, FakeOptions fakeOptions, IDummyValueCreationSession session, String failReasonForDefaultConstructor, Boolean throwOnFailure)
at FakeItEasy.Creation.FakeObjectCreator.CreateFake(Type typeOfFake, FakeOptions fakeOptions, IDummyValueCreationSession session, Boolean throwOnFailure)
at FakeItEasy.Creation.DefaultFakeAndDummyManager.CreateFake(Type typeOfFake, FakeOptions options)
at FakeItEasy.Creation.DefaultFakeCreatorFacade.CreateFake[T](Action`1 options)
at FakeItEasy.A.Fake[T](Action`1 options)
When I add the following, tests pass, but do it looks strange that I need to add it to all the fake creation:
var jobSuiteFilterApplier = A.Fake<IJobSuiteFilterApplier>(x => x.Strict().Synchronized());
public class CallSynchronizer : IInterceptionListener
{
private static readonly object SynchronizationLock = new object();
public void OnBeforeCallIntercepted(IFakeObjectCall interceptedCall)
{
Monitor.Enter(SynchronizationLock);
}
public void OnAfterCallIntercepted(ICompletedFakeObjectCall interceptedCall, IFakeObjectCallRule ruleThatWasApplied)
{
Monitor.Exit(SynchronizationLock);
}
}
public static class MyPersonalFakeExtensions
{
public static IFakeOptionsBuilder<T> Synchronized<T>(this IFakeOptionsBuilder<T> builder)
{
return builder.OnFakeCreated(fake => Fake.GetFakeManager(fake).AddInterceptionListener(new CallSynchronizer()));
}
}
Update: I am running the tests using ReSharper test runner on developer machine and using mstext.exe on build server. The concurrency settings allow for multiple tests to be run at once.
Update: FakeItEasy 2.0.0 has drastically improved support for tests run in parallel. Try it.
as mike z mentioned: FakeItEasy currently doesn't support multi-threaded tests. This is because not all internals are thread-safe, and it's not easy to make it completely thread-safe. There's an open issue, number 60, for supporting multi-threaded test execution.
For now the solution you provided is the only way to achieve this, as originally explained here http://hmemcpy.com/2012/12/running-multithreaded-unit-tests-with-fakeiteasy/.
There is no way to globally add an interception listener to all fakes, however you can use the FakeConfigurator<T>
class to automate this behaviour per type, so you could opt to include, for each faked type, a class such as
public class SomeTypeSynchronousConfigurator : FakeConfigurator<ISomeType>
{
public override void ConfigureFake(ISomeType fakeObject)
{
Fake.GetFakeManager(fakeObject)
.AddInterceptionListener(new CallSynchronizer());
}
}
FakeItEasy will discover the class and every new fake of (in this case) ISomeType
will have the synchronizer applied—you can make the fake just like var fake = A.Fake<ISomeType>();
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With