2014-10-22 4 views
5

간단한 intefrace를 가짜로 만들려고하면 FakeItEasy를 사용하는 유닛 테스트가 무작위로 실패합니다. 때때로 다른 테스트에서 발생하며 안정적이지 않습니다.테스트가 병렬로 실행될 때 FakeItEasy 가짜를 생성하지 못하는 경우가 있습니다.

: 여기
var jobSuiteFilterApplier = A.Fake<IJobSuiteFilterApplier>(x => x.Strict()); 

은 예외 사항입니다 :

여기
public interface IJobSuiteFilterApplier 
{ 
    JobSuiteDto FilterJobSuites(JobSuiteDto jobSuiteDto, JobSuiteFilter jobSuiteFilter); 
} 

는 가짜를 생성하고, 때로는 실패 코드의 조각이다 : 여기

내가 가짜에 필요한 샘플 인터페이스입니다
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) 

다음을 추가하면 테스트가 통과되지만 모든 fa에 추가해야한다는 것이 이상하게 보입니다. KE 생성 :

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())); 

    } 
} 

업데이트 : 개발자 컴퓨터에 ReSharper에서 테스트 러너를 사용하여 테스트를 실행하고 빌드 서버에 mstext.exe를 사용하고 있습니다. 동시성 설정을 사용하면 여러 테스트를 한 번에 실행할 수 있습니다.

+0

어떤 단위 테스트 프레임 워크를 사용하고 있습니까? 단위 테스트를 병렬로 실행하거나 여러 스레드에서 가짜를 작성합니까? 그건 [공개 문제] (https://github.com/FakeItEasy/FakeItEasy/issues/60) 인 것 같습니다. –

+0

죄송하지만 언급하지 않으 셨습니다. 나는 FakeItEasy를 사용하고 있습니다. 개발자 머신에서 ReSharper 테스트 러너를 사용하고 서버를 빌드 할 때 mstext.exe를 사용하여 테스트를 실행하고 있습니다. –

답변

10

업데이트 : FakeItEasy 2.0.0은 병렬 실행 테스트가 크게 향상되었습니다. 시도 해봐.

mike z 언급 : FakeItEasy는 현재 멀티 스레드 테스트를 지원하지 않습니다. 이는 모든 내부가 스레드로부터 안전하지는 않기 때문에 완전히 스레드로부터 안전하게 보호하기가 쉽지 않기 때문입니다. 다중 스레드 테스트 실행을 지원하기 위해 공개 문제 (number 60)가 있습니다.

여기에 원래 설명한대로 http://hmemcpy.com/2012/12/running-multithreaded-unit-tests-with-fakeiteasy/과 같이 제공 한 솔루션 만 사용할 수 있습니다.

그러나 당신이 유형 당이 동작 을 자동화 할 FakeConfigurator<T> 클래스를 사용할 수 있습니다, 모두 가짜에 차단 리스너를 추가 전체적으로 할 수있는 방법이 없다, 그래서 당신은 포함하도록 선택할 수 있습니다, 각각 같은 유형, 클래스를 위조에 대한

public class SomeTypeSynchronousConfigurator : FakeConfigurator<ISomeType> 
{ 
    public override void ConfigureFake(ISomeType fakeObject) 
    { 
     Fake.GetFakeManager(fakeObject) 
       .AddInterceptionListener(new CallSynchronizer()); 
    } 
} 

FakeItEasy이 discover the class (이 경우)의 모든 새로운 가짜 ISomeType이 싱크로 나이저를 적용 - 당신은 var fake = A.Fake<ISomeType>(); 같은 가짜를 만들 수있을 것이다 것입니다.

+0

답변 해 주셔서 감사합니다. –

+0

+1 필립은 답을하고 블레어 +1은 멋진 꾸밈을 제공합니다! –