Многопоточный код заставляет Rhino Mocks вызывать взаимную блокировку

В настоящее время мы сталкиваемся с некоторыми проблемами во время модульного тестирования. Наш класс выполняет многопоточную обработку некоторых вызовов функций для Mocked-объектов с помощью Rhino Mocks. Вот пример, сокращенный до минимума:

public class Bar
{
    private readonly List<IFoo> _fooList;

    public Bar(List<IFoo> fooList)
    {
        _fooList = fooList;
    }

    public void Start()
    {
        var allTasks = new List<Task>();
        foreach (var foo in _fooList)
            allTasks.Add(Task.Factory.StartNew(() => foo.DoSomething()));

        Task.WaitAll(allTasks.ToArray());
    }
}

Интерфейс IFoo определяется как:

public interface IFoo
{
    void DoSomething();
    event EventHandler myEvent;
}

Для воспроизведения тупиковой ситуации наш unittest делает следующее: 1. создайте несколько IFoo Mocks 2. Вызов myEvent при вызове DoSomething ().

[TestMethod]
    public void Foo_RaiseBar()
    {
        var fooList = GenerateFooList(50);

        var target = new Bar(fooList);
        target.Start();
    }

    private List<IFoo> GenerateFooList(int max)
    {
        var mocks = new MockRepository();
        var fooList = new List<IFoo>();

        for (int i = 0; i < max; i++)
            fooList.Add(GenerateFoo(mocks));

        mocks.ReplayAll();
        return fooList;
    }

    private IFoo GenerateFoo(MockRepository mocks)
    {
        var foo = mocks.StrictMock<IFoo>();

        foo.myEvent += null;
        var eventRaiser = LastCall.On(foo).IgnoreArguments().GetEventRaiser();

        foo.DoSomething();
        LastCall.On(foo).WhenCalled(i => eventRaiser.Raise(foo, EventArgs.Empty));

        return foo;
    }

Чем больше генерируется Foo, тем чаще возникает взаимоблокировка. Если тест не блокирует, запустите его несколько раз, и он будет. Остановка тестового запуска отладки показывает, что все задачи по-прежнему находятся в TaskStatus.Running, а текущий рабочий поток прерывается на

[В спящем режиме, подождите или присоединяйтесь]
Rhino.Mocks.DLL! Rhino.Mocks.Impl.RhinoInterceptor.Intercept (Castle.Core.Interceptor.IInvocation invocation) + 0x3d bytes

Самая странная вещь, которая нас больше всего сбивает с толку, это то, что сигнатура метода Intercept (...) определена как синхронизированная, но здесь расположены несколько потоков. Я прочитал несколько сообщений о Rhino Mocks и Multithreaded, но не обнаружил предупреждений (ожидаемая установка записей) или ограничений.

 [MethodImpl(MethodImplOptions.Synchronized)]
    public void Intercept(IInvocation invocation)

Мы делаем что-то совершенно неправильно при настройке наших Mockobjects или их использовании в многопоточной среде? Любая помощь или подсказка приветствуются!

9
задан Benjamin 3 February 2014 в 14:05
поделиться