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

Как остановить все тесты из теста или setUp с помощью unittest?

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

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

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

4b9b3361

Ответ 1

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

Во-первых, я добавил новое исключение:

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.

Ответ 2

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

Ответ 3

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

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

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

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

Ответ 4

В тестовом цикле 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)

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

Ответ 5

Я просмотрел класс 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 всюду, это не проблема для меня.

Ответ 6

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

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