2016-03-29 3 views
6

Давайте представим, у меня есть следующий метод, который должен быть испытан:Как избежать Thread.sleep в модульных тестах?

@Autowired 
private RoutingService routingservice; 

public void methodToBeTested() { 
    Object objectToRoute = initializeObjectToRoute(); 
    if (someConditions) { 
     routingService.routeInOneWay(objectToRoute); 
    } else { 
     routingService.routeInAnotherWay(objectToRoute); 
    } 
} 

В этом случае RoutingService выполняется в отдельном потоке, таким образом, в его конструкторе мы имеем следующее:

Thread thread = new Thread(this); 
thread.setDaemon(true); 
thread.start(); 

Проблема заключается в том, что RoutingService меняет состояние objectToRoute, и это именно то, что я хочу проверить, но это не происходит сразу, поэтому тест терпит неудачу. Однако, если я добавлю Thread.sleep(), тогда он работает, но это плохая практика, как я знаю.

Как я могу избежать Thread.sleep() в этом случае?

+0

Использование «Thread.sleep» в модульном тесте - это не плохая практика, так как все, что вы делаете, это имитировать прохождение времени, которое необходимо для некоторых модульных тестов. Причина, по которой люди говорят, что использование «Thread.sleep» - это плохая практика, заключается в том, что иногда она используется как попытка исправить состояние гонки. Используете ли вы только «Thread.sleep» в тестах или в исходном коде? –

+0

Когда вы тестируете резьбовой код, как бы вы гарантировали, что ваши юнит-тесты не будут шелушатся? То, что они всегда выполняются детерминированным образом. Я думаю, что насмехается над классом Service is better opiton –

+0

Я использую сон только в тестах, но обнаружил немало мест, где люди упоминают, что обычно сон не так хорош в модульных тестах.Например, плагин SonarLint жалуется и говорит, что это нарушение, и дает следующее описание: «Использование Thread.sleep в тесте - это, как правило, плохая идея. Он создает хрупкие тесты, которые могут непредсказуемо выходить из строя в зависимости от среды (« Проходит моя машина! ") или загрузить." – Rufi

ответ

4

Если вы тестируете methodToBeTested, вы должны просто высмеять routingservice. Вы не должны тестировать какие-либо методы, которые звонят methodToBeTested. Однако, похоже, вы хотите протестировать RoutingService (вы сказали: «Проблема в том, что RoutingService меняет состояние objectToRoute, и это именно то, что я хочу проверить»). Чтобы протестировать методы RoutingService, вы должны написать отдельные модульные тесты для этих методов.

+0

Да, это может быть один из способов, однако я не могу сказать, что мне это нравится. Скорее всего, мой тест переходит от теста Unit к тесту интеграции. RoutingService проверен, но в этом случае я хочу проверить, что при определенных условиях маршрутизация, однако, может занять некоторое время. Конечно, я могу издеваться над RoutingService и проверять, что был вызван конкретный метод, но я не буду закрывать изменение состояния. – Rufi

+0

Да, я бы сказал, если вы хотите это сделать, он станет интеграционным тестом и не должен запускаться с обычным набором модульных тестов. модульные тесты должны выполняться быстро и последовательно, поэтому разработчики могут запускать их все перед проверкой любого кода. У вас есть отдельный набор интеграционных тестов, которые запускаются на регулярной основе (например, через Jenkins) – forgivenson

0

Вы можете высмеять objectToRoute, чтобы установить значение CompletableFuture, а затем позвоните по номеру get по этому поводу в вашем утверждении. Это будет продолжаться до тех пор, пока значение не будет установлено до продолжения. Затем установите тайм-аут @Test(timeout=5000) в случае, если значение никогда не установлено.

Это имеет то преимущество, что тест не будет ждать дольше, чем необходимо, и сложнее сбой из-за слишком короткого времени, потому что вы можете сделать тайм-аут намного большим, чем обычно.

0

зависит от цели. Как сказал Бен Грин в своем комментарии, сон опасен в тестах, потому что он может скрыть состояние гонки. Вы,, знаете, если общий дизайн содержит такое состояние гонки, где служба может быть использована до того, как маршрут будет готов. Он это делает, вы должны исправить это в коде, например, проверив условие ready и протестируйте его так же в своем тестовом классе.

Если вы знаете, что этого не может быть, вы должны задокументировать его в своем основном коде и в вашем тестовом классе. Это было бы прекрасным оправданием сна.

(я предполагаю, что это для интеграционного теста - для модульных тестов издевается должно быть достаточно, как вы сказали, в других ответах)

0

Вместо того, чтобы избежать Thread.sleep(), Вы можете передать значение, как ноль в тестовом примере Junit.

Смежные вопросы