Вопрос по unit-testing, java, sleep, testing – Тестирование с Thread.sleep

8

Каковы рекомендуемые подходы к использованиюThread.sleep() ускорить тесты.

Я тестирую сетевую библиотеку с функцией повторных попыток, когда соединения разрываются или возникают ошибки тайм-аута и т. Д. Библиотека, однако, используетThread.sleep() между повторными попыткамиt подключаться тысячи раз, пока сервер перезагружается). Вызов значительно замедляет юнит-тесты, и мне интересно, какие есть варианты переопределить его.

Обратите внимание, яЯ открыт для фактического изменения кода или использования фальшивой среды для насмешки Thread.sleep (), но сначала хотел бы услышать ваше мнение / рекомендацию.

Не используйте Thread.sleep (), используйте подход wait (). Thread.sleep () использует циклы процессора, а wait () - нет. Daniel Hiller
это можно рассматривать как пример для модульного тестирования с насмешками dfa

Ваш Ответ

6   ответов
2

почему вы пытаетесь проверить Thread.sleep. Кажется, япытаемся проверить поведение как следствие какого-то события.

то есть что произойдет, если:

время соединения вышлосоединение разорвано

Если вы моделируете код, основанный на событиях, вы можете проверить, что должно произойти, если произошло конкретное событие, вместо того, чтобы придумать конструкцию, которая маскирует параллельные вызовы API. И еще, что вы на самом деле тестируете? Вы тестируете, как ваше приложение реагирует на различные раздражители, или просто проверяете, работает ли JVM правильно?

Я согласен с другими читателями, что иногда этополезно помещать абстракцию вокруг любого кода, связанного со временем или потоком, т.е. виртуальных часовhttp://c2.com/cgi/wiki?VirtualClock так что вы можете смоделировать любое временное / параллельное поведение и сосредоточиться на поведении самого устройства.

Также звучит так, как будто вы должны принять шаблон состояния, чтобы ваш объект имел определенное поведение в зависимости от того, в каком состоянии он находится.s in. Т.е. AwaitingConnectionState, ConnectionDroppedState. Переход в разные состояния будет происходить через разные события, например, время ожидания, обрыв соединения и т. Д. Не уверен, что это излишне для ваших нужд, но, безусловно, удаляет много условной логики, которая может сделать код более сложным и неясным.

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

3

ение по умолчанию. Таким образом, в ваших модульных тестах вызовите установщик с небольшим аргументом (например, 1), а затем выполните метод, который вызовет.Thread.sleep()

Другой подобный подход заключается в том, чтобы сделать, если настраивается через логическое значение, так чтоThread.sleep() ISN»звонил вообще, еслиboolean установлен в.false

3

и я создал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();

1

создай свой собственный компонент, чтобы обернуть систему, которая тебе не подвластна. Просто сделал это сам, подумав, что яделюсь, это известно как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»

13

ным компонентам. Это включает получение текущего времени, а также задержки, такие как Thread.sleep (). Таким образом, во время тестирования легко заменить этот компонент на макет, а также переключиться на другую реализацию.

@ Notnoop Именно то, что я сделал сClock учебный класс. Поддерживает основные операции, такие как,,Clock.now()Clock.freeze()Clock.freeze(pointInTime) и так далее. Ни один компонент не взаимодействует со средой выполнения напрямую для извлечения времени, а наоборот.Clock Sayo Oladeji
Путь Таким образом, вы также можете установить свою конфигурацию или даже пропустить все что угодно в одном месте, а не распространять эту логику через код. Eugene Kuleshov
у нас был соблазн создатьMachine класс, чтобы абстрагироваться от всего этого. notnoop
2

который представляет политику для задержек повторения. Вызвать некоторый метод для типа политики для задержки. Издевайся как хочешь. Нет условной логики или /truefalse флаги. Просто введите тип, который вы хотите.

В 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
    }
}
Это не просто политика, а настраиваемый исполнитель сна. Политика будет только представлять стратегию вокруг сна, а не выполнять ее. В остальном, здравая идея. Adriaan Koster

Похожие вопросы