Как моделировать concurrency в модульных тестах?
Я новичок в модульном тестировании и в настоящее время немного экспериментирую с инструментами тестирования Visual Studio.
Мой вопрос - как определить утверждения о параллельном поведении в этих тестах. Например. если класс BoundedChan<T>
реализует ограниченный канал, как я могу указать тесты, например
- "
channel.Send
не будет блокировать" или
- "Если пропускная способность канала превышена,
channel.Send
будет блокироваться до тех пор, пока не будет прочитано значение"
Есть ли элегантное решение для написания этих утверждений?
Ответы
Ответ 1
Здесь статья в блоге, в которой обсуждается тема; он фокусируется на NUnit.
К сожалению, concurrency по-прежнему является областью модульного тестирования, что сложно структурировать. Это не простая проблема и по-прежнему требует, чтобы вы реализовали в своей тестовой версии некоторые из ваших собственных алгоритмов синхронизации и concurrency.
В примере, который вы предоставляете, может быть невозможно написать тест, который окончательно продемонстрирует, что метод будет или не будет блокироваться при определенных условиях. Возможно, вы сможете достичь некоторого уровня уверенности, сначала создав в худшем случае обстоятельства, в которых вы ожидаете поведения блокировки, а затем напишите тесты, чтобы определить, происходит это или нет.
Ответ 2
Этот вопрос может привести к достаточному содержанию, чтобы заполнить книгу.
В общем, я бы не рекомендовал добавлять модульные тесты к вашим классам для параллельных сценариев. С практикой, я думаю, вы узнаете, что автоматические модульные тесты имеют один или несколько "сладких пятен", и что сосредоточение усилий в этих областях (и использование других практик в других областях) дает более высокую рентабельность инвестиций.
Но ваш класс, по-видимому, около concurrency (не может точно определить на основе предоставленной информации), и поэтому это может быть случай, когда вам действительно нужен тест concurrency -simulating.
Вы можете (насколько мне известно) запустить несколько потоков в unit test, если хотите. Но может быть и более простой способ. Подумайте об использовании шаблона Compose Method. Хотя речь идет о предмете - эта схема довольно важна для эффективных модульных тестов для всех, а не только с помощью concurrency.
Ответ 3
Я создал помощника, который может запустить кучу потоков для выполнения одновременных действий. Помощник предоставляет примитивы синхронизации и механизмы регистрации.
Его можно использовать в сочетании с любой инфраструктурой unit test. Вот фрагмент кода из unit test:
[Test]
public void TwoCodeBlocksInParallelTest()
{
// This static method runs the provided Action delegates in parallel using threads
CTestHelper.Run(
c =>
{
Thread.Sleep(1000); // Here should be the code to provide something
CTestHelper.AddSequenceStep("Provide"); // We record a sequence step for the expectations after the test
CTestHelper.SetEvent();
},
c =>
{
CTestHelper.WaitEvent(); // We wait until we can consume what is provided
CTestHelper.AddSequenceStep("Consume"); // We record a sequence step for the expectations after the test
},
TimeSpan.FromSeconds(10)); // This is a timeout parameter, if the threads are deadlocked or take too long, the threads are terminated and a timeout exception is thrown
// After Run() completes we can analyze if the recorded sequence steps are in the correct order
Expect(CTestHelper.GetSequence(), Is.EqualTo(new[] { "Provide", "Consume" }));
}
Он может использоваться для тестирования клиента/сервера или синхронизации в компонентах или просто запуска потока с таймаутом. Я продолжу улучшать это в ближайшие недели. Вот страница проекта:
Concurrency Помощник по тестированию
Ответ 4
Это должно быть interesring read → http://c2.com/cgi-bin/wiki?ExtremeProgrammingChallengeFourteen