如何修复挂起TeamCity构建的多线程单元测试

本文关键字:多线程 单元测试 构建 TeamCity 何修复 挂起 | 更新日期: 2023-09-27 18:13:36

我们面临的问题是,在TeamCity的CI中,我们的一个单元测试在一天中失败了几次。我们使用MSTest和RhinoMocks。在开发机器上复制它几乎是不可能的(可能是因为开发机器上只有一个cpu PC,我不知道)。

[TestMethod]
[TestCategory("UnitTest")]
[ExpectedException(typeof(AggregateException))]
public void TestRiskDataStagingThrowAggregateException()
{
    DataStagingThrowException(typeof(DeskRiskDataPump));
}
protected void DataStagingThrowException(Type dataPumpType)
{
    // set expectations
    foreach (IUploader uploader in StubUploaders)
    {
        uploader.Expect(x => x.Upload(StubDataProvider)).Repeat.Once().Throw(new Exception("BANG!!!"));
    }
    Repository.ReplayAll();
    IDataPump datapump = new DataPumpFactory().GetDataPump(dataPumpType, StubDataProvider, StubUploaders, StubDistributor);
    // Execute
    // the test can hang here!!!
    datapump.Execute();
    Repository.VerifyAll();
}
StubDataProvider = Repository.Stub<IEnumerable<TRecord>>();
StubUploaders = new List<IUploader>();
StubDistributor = Repository.Stub<IDataDistributor>();
StubUploaders.Add(Repository.Stub<IUploader>());
StubUploaders.Add(Repository.Stub<IUploader>());
StubUploaders.Add(Repository.Stub<IUploader>());

实现IDataPump的类有点复杂,我不敢在这里发布:)一般来说,它实现了生产者-消费者模式,并在不同的流中启动了一些进程,就像这样

Task[] tasks = new Task[4];
// Start adding to the queue
tasks[0] = Task.Factory.StartNew(Produce);
// Start draining the queue in parallel
tasks[1] = Task.Factory.StartNew(ConsumeCreditRisk);
tasks[2] = Task.Factory.StartNew(ConsumeTrancheRisk);
tasks[3] = Task.Factory.StartNew(ConsumeRatesRisk);
// Wait to complete
try
{
    Task.WaitAll(tasks);
}
catch (AggregateException e)
{
    .....
    throw;
}
private void ConsumeCreditRisk()
{
    _creditRiskUploader.Upload(_creditRiskBuffer.GetConsumingEnumerable());
}

在我们的例子中,上传器是存根,它应该抛出一个异常,它应该作为一个聚合异常被捕获。但根据日志,它有时会挂在存根方法上传。

你认为是什么原因导致了这个问题?

如何修复挂起TeamCity构建的多线程单元测试

实际上,您需要为任何多线程测试提供一个超时,以防止死锁破坏您的构建。