Moq still doesn't support multithreading #91

Open
VitaliyKurokhtin opened this Issue Feb 11, 2014 · 0 comments

Projects

None yet

1 participant

@VitaliyKurokhtin

Just came across following issue with Moq (4.2.1312.1622). Consider interface:

public IMyInterface
{
void Do(int arg);
}

... setup:
var mock = Mock.Create();
mock.Setup(x => x.Do(0)).Verifiable();
mock.Setup(x => x.Do(1)).Verifiable();

... and invocation:

var obj = mock.Object;
var t1 = Task.Run(() => obj.Do(0));
var t2 = Task.Run(() => obj.Do(1));

Task.WhenAll(t1, t2).Wait();
mock.Verify();

Every now and then this verification will fail saying that one of two setups was not matched. But will succeed if changed to:

mock.Verify(x => x.Do(0), Times.Once);
mock.Verify(x => x.Do(1), Times.Once);

This happens because method call invocation logic inside Interceptor is not thread safe. When Interceptor.Intercept method is called it creates strategy pipeline, one of strategies in this pipeline - ExtractProxyCall - locates matched method call and places it into InterceptStrategyContext.CurrentCall. Which is later used by ExecuteCall strategy to do the actual call.

The problem here is that both executing threads will work with same InterceptorContext instance. So when executed in parallel it's possible of one ExtractProxyCall strategy to overwrite method call just located by another ExtractProxyCall strategy, that way both ExecuteCall strategies will end up executing same method call twice. This can easily be confirmed by attaching callbacks to original setups.

mock.Verify(x => ...) on the other hand does verification evaluating given expression against collected call contexts which, obviously, contains correct information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment