Подтвердить что ты не робот

PHPUnit - автоматически повторить неудачные тесты X раз?

У меня есть сложный набор тестов PHPUnit, некоторые из которых связаны с подключением к серверам по всему миру, которые по какой-то причине иногда включают таймаут.

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

Теперь я понимаю, что это может быть не лучший способ справиться с моей ситуацией. Лучшим решением было бы исправить серверы. Но сейчас это не в моих силах.

Итак, что мне действительно очень нравится, это способ сказать PHPUnit повторно протестировать каждый неудачный тестовый файл X раз и только пометить его как сбой, если он сработал каждый раз.

Любые идеи?

Изменить: многие из вас ответили полезными предложениями, что я этого не делаю. Я понимаю, спасибо. Однако именно то, что я пытаюсь сделать, это создать тестовый пакет, который проверяет работу всей системы, включая удаленные серверы. Я понимаю концепцию тестирования некоторых частей моего кода с помощью "макетных" ответов от снаружи... но я также лучше спал ночью, если часть моих тестов проверяет "полный стек".

4b9b3361

Ответ 1

Поскольку PHPUnit не поддерживает это поведение из коробки, вам нужно закодировать цикл самостоятельно. Вместо того, чтобы делать это в каждом тестировании, который требует этого, создайте собственный базовый класс тестового примера (если вы еще этого не сделали), который расширяет PHPUnit_Framework_TestCase и предоставляет эту функцию.

Вы можете либо получить фантазию, либо переопределить testBare(), чтобы проверить аннотацию, такую ​​как @retry 5, зациклировать это число раз, вызывая parent::testBare() и проглатывать все исключения (или подмножество), кроме последнего.

public function runBare() {
    // I'll leave this part to you. PHPUnit supplies methods for parsing annotations.
    $retryCount = $this->getNumberOfRetries();
    for ($i = 0; $i < $retryCount; $i++) {
        try {
            parent::runBare();
            return;
        }
        catch (Exception $e) {
            // last one thrown below
        }
    }
    if ($e) {
        throw $e;
    }
}

Или вы можете создать аналогичный вспомогательный метод, который принимает количество повторений и закрытие/вызываемый как параметры и вызывает его из каждого теста, который ему нужен.

public function retryTest($count, $test) {
    // just like above without checking the annotation
    ...
        $test();
    ...
}

public function testLogin() {
    $this->retryTest(5, function() {
        $service = new LoginService();
        ...
    });
}

Ответ 2

Не совсем ответ на ваш вопрос, но я все равно скажу: ваши тесты никогда не должны включать удаленные ресурсы (особенно когда они полностью вышли из вашей руки (в отличие от локальных зеркал)). Вы должны инкапсулировать свои соединения в отдельные классы (например, Connection), и в рамках ваших тестов вы издеваетесь над этими объектами и работаете со статическими ответами, которые вернут ваши удаленные хосты.

Ответ 3

Вместо того, чтобы подключаться к живым серверам, разве вы не должны использовать макетные объекты и приспособления, чтобы ответы из других источников не влияли на ваши тесты?

Вы можете использовать инъекцию зависимостей для использования конкретного HTTP-клиента, который вернет код данных и ответа, который вы ему скажете (в зависимости от того, как написан ваш код). В идеале, ваши модульные тесты должны быть независимы от внешних воздействий; вы должны контролировать то, что вы тестируете, и, например, принудительная ошибка 404 или 500 должна быть отдельной частью ваших тестов.

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

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

Ответ 4

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

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

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

В противном случае, если вы хотите автоматизировать больше, вы можете реализовать PHPUnit_Framework_TestListener, сохранить количество неудавшихся тестов в ассоциативном массиве и сравнить с тестовые прогоны. Не уверен, насколько это возможно, но вы можете попробовать.

Ответ 5

Вы должны иметь возможность создать утверждение соединения с БД и реализовать этот тест в своих других тестах "как" ваше соединение с БД. Внутри этого теста вы можете попробовать столько раз, сколько вам нужно, и вернуть false после попытки X.