我正在尝试对一个对视频文件进行多线程处理的类进行单元测试。被测试的类是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;
}
}