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

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

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

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

6 ответов


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

# 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 стиль.


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

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

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.


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

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

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

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


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

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


Я посмотрел на TestCase class и решил подкласс его. Класс просто переопределяет 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 везде, это не проблема для меня.


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

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