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

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

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

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

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

Есть идеи?

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

5 ответов

Решение

Поскольку 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();
        ...
    });
}

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

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

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

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

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

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

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

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

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

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

Другие вопросы по тегам