Вопрос по unit-testing, java, sleep, testing – Тестирование с Thread.sleep
Каковы рекомендуемые подходы к использованиюThread.sleep()
ускорить тесты.
Я тестирую сетевую библиотеку с функцией повторных попыток, когда соединения разрываются или возникают ошибки тайм-аута и т. Д. Библиотека, однако, используетThread.sleep()
между повторными попыткамиt подключаться тысячи раз, пока сервер перезагружается). Вызов значительно замедляет юнит-тесты, и мне интересно, какие есть варианты переопределить его.
Обратите внимание, яЯ открыт для фактического изменения кода или использования фальшивой среды для насмешки Thread.sleep (), но сначала хотел бы услышать ваше мнение / рекомендацию.
почему вы пытаетесь проверить Thread.sleep. Кажется, япытаемся проверить поведение как следствие какого-то события.
то есть что произойдет, если:
время соединения вышлосоединение разорваноЕсли вы моделируете код, основанный на событиях, вы можете проверить, что должно произойти, если произошло конкретное событие, вместо того, чтобы придумать конструкцию, которая маскирует параллельные вызовы API. И еще, что вы на самом деле тестируете? Вы тестируете, как ваше приложение реагирует на различные раздражители, или просто проверяете, работает ли JVM правильно?
Я согласен с другими читателями, что иногда этополезно помещать абстракцию вокруг любого кода, связанного со временем или потоком, т.е. виртуальных часовhttp://c2.com/cgi/wiki?VirtualClock так что вы можете смоделировать любое временное / параллельное поведение и сосредоточиться на поведении самого устройства.
Также звучит так, как будто вы должны принять шаблон состояния, чтобы ваш объект имел определенное поведение в зависимости от того, в каком состоянии он находится.s in. Т.е. AwaitingConnectionState, ConnectionDroppedState. Переход в разные состояния будет происходить через разные события, например, время ожидания, обрыв соединения и т. Д. Не уверен, что это излишне для ваших нужд, но, безусловно, удаляет много условной логики, которая может сделать код более сложным и неясным.
Если вы подойдете таким образом, то вы все равно сможете протестировать поведение на модульном уровне, продолжая тестирование на месте с последующим интеграционным тестом или приемочным тестом.
ение по умолчанию. Таким образом, в ваших модульных тестах вызовите установщик с небольшим аргументом (например, 1), а затем выполните метод, который вызовет.Thread.sleep()
Другой подобный подход заключается в том, чтобы сделать, если настраивается через логическое значение, так чтоThread.sleep()
ISN»звонил вообще, еслиboolean
установлен в.false
и я создалSleeper
интерфейс, чтобы абстрагироваться от этого:
public interface Sleeper
{
void sleep( long millis ) throws InterruptedException;
}
Реализация по умолчанию использует:Thread.sleep()
public class ThreadSleeper implements Sleeper
{
@Override
public void sleep( long millis ) throws InterruptedException
{
Thread.sleep( millis );
}
}
В моих модульных тестах я ввожу:FixedDateTimeAdvanceSleeper
public class FixedDateTimeAdvanceSleeper implements Sleeper
{
@Override
public void sleep( long millis ) throws InterruptedException
{
DateTimeUtils.setCurrentMillisFixed( DateTime.now().getMillis() + millis );
}
}
Это позволяет мне запрашивать время в модульном тесте:
assertThat( new DateTime( DateTimeUtils.currentTimeMillis() ) ).isEqualTo( new DateTime( "2014-03-27T00:00:30" ) );
Обратите внимание, что вам нужно исправить время, прежде чем использоватьDateTimeUtils.setCurrentMillisFixed( new DateTime( "2014-03-26T09:37:13" ).getMillis() );
в начале теста и восстановите время снова после теста, используяDateTimeUtils.setCurrentMillisSystem();
создай свой собственный компонент, чтобы обернуть систему, которая тебе не подвластна. Просто сделал это сам, подумав, что яделюсь, это известно какSelfShunt» Проверь это:
Generator
это класс, который, когда вы звонитеgetId()
возвращает текущее системное время.
public class GeneratorTests implements SystemTime {
private Generator cut;
private long currentSystemTime;
@Before
public void setup(){
cut = Generator.getInstance(this);
}
@Test
public void testGetId_returnedUniqueId(){
currentSystemTime = 123;
String id = cut.getId();
assertTrue(id.equals("123"));
}
@Override
public long currentTimeMillis() {
return currentSystemTime;
}
}
Мы делаем тестовый класс »SelfShunt» и стать компонентом SystemTime таким образом, чтобы у нас был полный контроль над временем.
public class BlundellSystemTime implements SystemTime {
@Override
public long currentTimeMillis(){
return System.currentTimeMillis();
}
}
Мы оборачиваем компонент, который нет под нашим контролем.
public interface SystemTime {
long currentTimeMillis();
}
Затем создайте интерфейс, чтобы наш тестSelfShunt»
ным компонентам. Это включает получение текущего времени, а также задержки, такие как Thread.sleep (). Таким образом, во время тестирования легко заменить этот компонент на макет, а также переключиться на другую реализацию.
Clock
учебный класс. Поддерживает основные операции, такие как,,Clock.now()
Clock.freeze()
Clock.freeze(pointInTime)
и так далее. Ни один компонент не взаимодействует со средой выполнения напрямую для извлечения времени, а наоборот.Clock
Machine
класс, чтобы абстрагироваться от всего этого.
который представляет политику для задержек повторения. Вызвать некоторый метод для типа политики для задержки. Издевайся как хочешь. Нет условной логики или /true
false
флаги. Просто введите тип, который вы хотите.
В ConnectRetryPolicy.java
public interface ConnectRetryPolicy {
void doRetryDelay();
}
В SleepConnectRetryPolicy.java
public class final SleepConnectRetryPolicy implements ConnectRetryPolicy {
private final int delay;
public SleepConnectRetryPolicy(final int delay) {
this.delay = delay;
}
@Override
public void doRetryDelay() {
try {
Thread.sleep(delay);
} catch (InterruptedException ie) {
log.error("connection delay sleep interrupted", ie);
}
}
}
В MockConnectRetryPolicy.java
public final class MockConnectRetryPolicy implements ConnectRetryPolicy {
@Override
public void doRetryDelay() {
// no delay
}
}