2

我正在尝试对一个对视频文件进行多线程处理的类进行单元测试。被测试的类是ParallelTranscoder。

ParallelTranscoder 依赖于工厂为其队列中的每个项目创建一个新的转码器。所以我正在创建一个存根 IAsyncTranscoder 和一个存根 IAsyncTranscoderFactory。然后我将 transcoderStub 提供给工厂,以便在调用 transcoderFactoryStub.Create() 时分发它。

IAsyncTranscoder 需要在完成处理后引发事件,因此设置存根以在调用 TranscodeAsync() 时立即引发它的 FinishedEvent。

所有这些都在第一个测试方法中起作用,我只将一个项目排入队列。但是,在第二种测试方法中,它失败并显示以下消息:

System.AggregateException :发生一个或多个错误。
----> System.AggregateException : 发生一个或多个错误。
----> System.InvalidOperationException : 当模拟对象处于重放状态时,此操作无效。

引发异常的行似乎transcoderStub.Raise(t => t.FinishedEvent += null,...在 CreateTranscoderStub() 方法内部。

这是因为 Rhino Mocks 可能不是线程安全的,还是我做错了?(我是 Rhino Mocks 的新手)

不管是什么原因,有没有办法做到这一点?

[TestFixture]
class ParallelTranscoderTests {

    [Test]
    public void Transcode_FinishWithoutError_RaisesFinishedEvent() {

        var transcoderStub = CreateTranscoderStub();

        var transcoderFactoryStub = MockRepository.GenerateStub<IAsyncTranscoderFactory>();
        transcoderFactoryStub.Stub(stub => stub.Create()).Return(transcoderStub);

        bool transcodingFinishedEventWasRaised = false;

        var transcoderUnderTest = new ParallelTranscoder(concurrencyLevel: -1, transcoderFactory: transcoderFactoryStub);

        // Subscribe to the event and set a flag if it's called
        transcoderUnderTest.FinishedEvent += (sender, args) => { transcodingFinishedEventWasRaised = true; };

        transcoderUnderTest.EnqueueTranscodeItem(new TranscodeItem());
        transcoderUnderTest.Transcode();

        Assert.That(transcoderUnderTest.TranscodingFinished, Is.True);
        Assert.That(transcodingFinishedEventWasRaised, Is.True);
    }

    [Test]
    public void Transcode_TwoItemsFinishWithoutError_RaisesItemFinishedEventTwiceAndFinishedEventOnce() {

        var transcoderStub1 = CreateTranscoderStub();
        var transcoderStub2 = CreateTranscoderStub();

        var transcoderFactoryStub = MockRepository.GenerateStub<IAsyncTranscoderFactory>();

        transcoderFactoryStub.Stub(stub => stub.Create()).Return(transcoderStub1).Repeat.Once();
        transcoderFactoryStub.Stub(stub => stub.Create()).Return(transcoderStub2).Repeat.Once();

        int timesTranscodingFinishedEventWasRaised = 0;
        int timesItemFinishedEventWasRaised = 0;

        var transcoderUnderTest = new ParallelTranscoder(
                                            concurrencyLevel: -1,
                                            transcoderFactory: transcoderFactoryStub
                                      );

        transcoderUnderTest.FinishedEvent += (sender, args) => {
            timesTranscodingFinishedEventWasRaised++;
        };
        transcoderUnderTest.ItemFinishedEvent += (sender, args) => {
            timesItemFinishedEventWasRaised++;
        };

        transcoderUnderTest.EnqueueTranscodeItem(new TranscodeItem(){InFile = "item1_in", OutFile = "item1_out"});
        transcoderUnderTest.EnqueueTranscodeItem(new TranscodeItem(){InFile = "item2_in", OutFile = "item2_out"});

        transcoderUnderTest.Transcode();

        Assert.That(transcoderUnderTest.TranscodingFinished, Is.True);
        Assert.That(timesTranscodingFinishedEventWasRaised, Is.EqualTo(1));
        Assert.That(timesItemFinishedEventWasRaised, Is.EqualTo(2));

    }

    private static IAsyncTranscoder CreateTranscoderStub() {
        var transcoderStub = MockRepository.GenerateStub<IAsyncTranscoder>();
        transcoderStub.Stub(stub => stub.TranscodingFinished).Return(true);
        transcoderStub.Stub(stub => stub.TranscodeAsync()).WhenCalled(delegate {
            transcoderStub.Raise(t => t.FinishedEvent += null,
                                 transcoderStub,
                                 new TranscoderFinishedEventArgs
                                     (true, DateTime.Now,
                                      DateTime.Now, 0));
        });
        return transcoderStub;
    }
}
4

0 回答 0