PHPUnit - автоматически повторять неудачные тесты X раз? - PullRequest
11 голосов
/ 09 октября 2011

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

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

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

Есть идеи?

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

Ответы [ 5 ]

11 голосов
/ 09 октября 2011

Поскольку 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();
        ...
    });
}
6 голосов
/ 09 октября 2011

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

2 голосов
/ 09 октября 2011

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

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

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

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

1 голос
/ 09 октября 2011

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

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

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

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

0 голосов
/ 09 октября 2011

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

...