Как остановить все тесты изнутри теста или установки с помощью unittest? - PullRequest
18 голосов
/ 27 сентября 2010

Я расширяю инфраструктуру Python 2.7 unittest для тестирования некоторых функций.Одна из вещей, которую я хотел бы сделать, - остановить все тесты внутри теста и внутри метода setUpClass().Иногда, если тест завершается неудачно, программа настолько не работает, что больше не имеет смысла продолжать тестирование, поэтому я хочу остановить выполнение тестов.

Я заметил, что TestResult имеет атрибут shouldStopи метод stop(), но я не уверен, как получить доступ к нему внутри теста.

У кого-нибудь есть идеи?Есть ли лучший способ?

Ответы [ 7 ]

15 голосов
/ 29 сентября 2010

Если вам интересно, вот простой пример того, как вы могли бы самостоятельно принять решение о чистом выходе из набора тестов с помощью py.test :

# content of test_module.py
import pytest
counter = 0
def setup_function(func):
    global counter
    counter += 1
    if counter >=3:
        pytest.exit("decided to stop the test run")

def test_one():
    pass
def test_two():
    pass
def test_three():
    pass

и если вы запустите это, вы получите:

$ pytest test_module.py 
============== test session starts =================
platform linux2 -- Python 2.6.5 -- pytest-1.4.0a1
test path 1: test_module.py

test_module.py ..

!!!! Exit: decided to stop the test run !!!!!!!!!!!!
============= 2 passed in 0.08 seconds =============

Вы также можете поместить вызов py.test.exit() в тест или в плагин для конкретного проекта.

Sidenote: py.test изначально поддерживает py.test --maxfail=NUM для реализации остановки после сбоев NUM.

Sidenote2: py.test имеет ограниченную поддержку для запуска тестов в традиционном стиле unittest.TestCase.

4 голосов
/ 03 февраля 2012

Вот еще один ответ, который я придумал через некоторое время:

Сначала я добавил новое исключение:

class StopTests(Exception):
"""
Raise this exception in a test to stop the test run.

"""
    pass

затем я добавил новый assert в свой дочерний тестовый класс:

def assertStopTestsIfFalse(self, statement, reason=''):
    try:
        assert statement            
    except AssertionError:
        result.addFailure(self, sys.exc_info())

и последнее, что я переопределил функцию run, чтобы включить это прямо под вызовом testMethod():

except StopTests:
    result.addFailure(self, sys.exc_info())
    result.stop()

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

3 голосов
/ 27 сентября 2010

В настоящее время вы можете остановить тесты только на уровне набора. Как только вы попадаете в TestCase, метод stop() для TestResult не используется при итерации по тестам.

В некоторой степени связанный с вашим вопросом, если вы используете python 2.7, вы можете использовать флаг -f/--failfast при вызове теста с python -m unittest. Это остановит тест при первом сбое.

См. 25.3.2.1. параметры командной строки failfast, catch и buffer

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

1 голос
/ 10 июня 2014

В цикле тестирования unittest.TestSuite при запуске присутствует условие break:

class TestSuite(BaseTestSuite):

    def run(self, result, debug=False):
        topLevel = False
        if getattr(result, '_testRunEntered', False) is False:
            result._testRunEntered = topLevel = True

        for test in self:
            if result.shouldStop:
                break

Поэтому я использую пользовательский набор тестов, подобный этому:

class CustomTestSuite(unittest.TestSuite):
    """ This variant registers the test result object with all ScriptedTests,
        so that a failed Loign test can abort the test suite by setting result.shouldStop
        to True
    """
    def run(self, result, debug=False):
        for test in self._tests:
            test.result = result

        return super(CustomTestSuite, self).run(result, debug)

с пользовательским классом результатов теста, подобным этому:

class CustomTestResult(TextTestResult):
    def __init__(self, stream, descriptions, verbosity):
        super(CustomTestResult, self).__init__(stream, descriptions, verbosity)
        self.verbosity = verbosity
        self.shouldStop = False

, и мои классы теста выглядят так:

class ScriptedTest(unittest.TestCase):
    def __init__(self, environment, test_cfg, module, test):
        super(ScriptedTest, self).__init__()
        self.result = None

При определенных условиях я затем отменяю набор тестов;Например, набор тестов начинается с входа в систему, и если это не удается, мне не нужно пробовать остальное:

    try:
        test_case.execute_script(test_command_list)
    except AssertionError as e:
        if test_case.module == 'session' and test_case.test == 'Login':
            test_case.result.shouldStop = True
            raise TestFatal('Login failed, aborting test.')
        else:
            raise sys.exc_info()

Затем я использую набор тестов следующим образом:

    suite = CustomTestSuite()

    self.add_tests(suite)

    result = unittest.TextTestRunner(verbosity=self.environment.verbosity, stream=UnitTestLoggerStream(self.logger),
                                     resultclass=CustomTestResult).run(suite)

Я не уверен, есть ли лучший способ сделать это, но он ведет себя правильно для моих тестов.

0 голосов
/ 24 октября 2018

Использование:

if condition: 
   return 'pass'
0 голосов
/ 05 августа 2017

Несмотря на то, что вы не получите обычные отчеты о тестах, выполненных до сих пор, очень простой способ остановить тестовый запуск из метода TestCase - просто вызвать KeyboardInterrupt внутри метода.

Вы можете увидеть, как только KeyboardInterrupt может всплывать внутри unittest бегуна тестов, посмотрев код CPython здесь внутри testPartExecutor().

0 голосов
/ 28 сентября 2010

Я посмотрел на класс TestCase и решил сделать его подклассом.Класс просто переопределяет run().Я скопировал метод и, начиная со строки 318 в исходном классе, добавил:

# this is CPython specific. Jython and IronPython may do this differently
if testMethod.func_code.co_argcount == 2:
    testMethod(result)
else:
    testMethod()

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...