Оцените NUnit утверждение после задержки - PullRequest
0 голосов
/ 05 июля 2018

Я пытаюсь написать модульный тест с NUnit для метода, который может занять от 1 до 3 секунд. Для подтверждения теста все, что мне нужно сделать, это проверить, было ли увеличено значение List<string> entries в этом интервале от 1 до 3 секунд.

Мое текущее решение - использовать Thread.Sleep():

1. int currentEntries = entries.count;
2. Call methodA()
3. Thread.Sleep(3000);
4. int updatedEntries = entries.count;
5. Assert.That(updatedEntries, Is.EqualTo(currentEntries+1));

Это решение всегда занимает не менее 3 секунд, даже когда methodA () завершается быстрее.

Я пытался использовать ограничение задержки NUnits:

Assert.That(entries.Count, Is.EqualTo(currentEntries+1).After(3).Seconds.PollEvery(250).MilliSeconds);

Это было бы идеально, поскольку оно поддерживает опрос. Но ограничение After по-прежнему оценивается мгновенно, а не через 3 секунды, как обсуждено здесь .

Есть ли лучшее решение этой проблемы?

Ответы [ 2 ]

0 голосов
/ 05 июля 2018

Ваш вызов Assert.That имеет фактический аргумент, который оценивается непосредственно перед вызовом метода. Значение entries.Count берется, и полученное целочисленное значение копируется в качестве аргумента метода. В рамках метода мы имеем дело с константой.

Когда ограничение переоценивается каждые 250 миллисекунд, оно выполняется каждый раз для одной и той же скопированной константы, которая, конечно, никогда не меняется.

Когда вы используете отложенное ограничение, с опросом или без него, фактический аргумент должен быть в форме делегата, лямбды или ссылки на поле. Следующая простая модификация должна заставить его работать.

Assert.That (() => entries.Count, Is.EqualTo(currentEntries+1).After(3).Seconds.PollEvery(250).MilliSeconds);

В качестве альтернативы, это также должно работать

Assert.That (entries, Has.Count.EqualTo(currentEntries+1).After(3).Seconds.PollEvery(250).Milliseconds);

потому что свойство оценивается каждый раз, когда мы опрашиваем.

0 голосов
/ 05 июля 2018

Ответ Чарли прибивает вашу актуальную проблему (как всегда делают его ответы). Однако я настоятельно рекомендую не проводить тесты, которые зависят от задержек. Если ваш тест не пройден, как вы узнаете, была ли проблема в том, что вы просто не ждали достаточно долго.

Кроме того, если это часть автоматизированного набора тестов, затрачиваемое время на выполнение всех тестов станет чрезвычайно дорогим, если вы добавите больше таких тестов.

Хорошие тесты являются детерминированными. Например, см. Мартина Фаулера «Искоренение недетерминизма в тестах» , в котором есть фраза:

Никогда не используйте бодрствующий сон для ожидания асинхронных ответов: используйте обратный вызов или опрос.

Мое предложение состояло бы в том, чтобы реорганизовать ваш код, чтобы функциональность была отделена от потоков, и протестировать функциональность, а не часть потоков.

Как только это разделение будет достигнуто, коду, который вызывает функциональность потока, можно присвоить Mock, и вы можете просто проверить, что Mock был вызван, поскольку вы отдельно проверили, что он ведет себя правильно, хотя для этого все еще требуется опрос ... так:

Если вы инкапсулируете код, который запускает отдельный поток, то в своем тесте предоставьте средство запуска для имитации потока, которое фактически выполняет код синхронно. Поэтому, как только тестируемый код завершен, вы можете сделать утверждение, не дожидаясь.

...