#c# #teamcity #rhino-mocks
#c# #teamcity #rhino-издевается
Вопрос:
Мы столкнулись с проблемой, заключающейся в том, что один из наших модульных тестов несколько раз за день завершался неудачей во время CI на TeamCity. Мы используем MSTest и RhinoMocks. Это почти невозможно воспроизвести на компьютере разработчика (возможно, из-за 1 процессора на компьютере разработчика, я не знаю).
[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());
}
В нашем случае загрузчики — это заглушки, которые предполагают выдачу исключения, и оно должно быть перехвачено как совокупное исключение. Но, согласно журналам, он иногда зависает при загрузке метода stub.
У вас есть какие-либо предположения, что может вызвать проблему?
Комментарии:
1. Это почти наверняка какая-то проблема параллелизма. У вас есть свой собственный код блокировки или вы используете коллекции из System. Коллекции. Одновременный доступ задач к синхронизации к данным? Я бы рекомендовал добавить модульный тестовый цикл, который выполняет ваш тест локально навсегда.. это должно позволить вам (в конечном итоге) испытывать такое же зависание, даже когда отладчик подключен.
2. спасибо за совет, я попробую. Для организации буфера мы используем BlockingCollection. Этот код прошел сложный нагрузочный тест … он должен зависнуть в таком простом модульном тесте
Ответ №1:
На самом деле вам нужно предоставить тайм-аут для любых многопоточных тестов, чтобы предотвратить взаимоблокировки, которые могут испортить вашу сборку. Однако это обходной путь.