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

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

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

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

 Jonathan Hartley08 мар. 2017 г., 21:04
Я использую это, чтобы прервать тестовый прогон перед запуском любых тестов, если тестируемое приложение настроено с настройками prod. (на самом деле, с любыми не тестовыми настройками.)

Ответы на вопрос(7)

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

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

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

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

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

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

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

 user19767427 сент. 2010 г., 22:17
Благодарю. Я видел опцию failfast, но я не всегда хочу потерпеть неудачу при первой ошибке, только в выбранных местах. Я думаю, что я должен отредактировать свой вопрос, чтобы упомянуть, что я использую Python 2.7.
Решение Вопроса

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

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

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 кода.

 Mayra Delgado21 мар. 2017 г., 10:17
Где проводятся СтопТесты?

В тестовом циклеunittest.TestSuite, Eсть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)

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

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

Примечание:py.test изначально поддерживаетpy.test --maxfail=NUM осуществить остановку после сбоев NUM.

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

 RvdK10 апр. 2014 г., 10:24
Текущая версия Py.Test: импортировать pytest, а затем вы можете сделать pytest.exit («ваше сообщение»)
 Jonathan Hartley08 мар. 2017 г., 21:06
Это также хорошо работает в приспособлении pytest, объявленном в файле conftest.py, с scope = 'session', autouse = True. Это будет выполняться перед каждым тестом в проекте. Вызов pytest.exit отсюда может прервать весь тестовый запуск перед выполнением любого теста. Я использую это, чтобы прервать тесты, если они выполняются с использованием prod config (фактически любой не тестовый config)
 user19767404 окт. 2010 г., 20:42
Благодарю. Я не знал об этой структуре тестирования. Я посмотрю на это.

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

if condition: 
   return 'pass'

Ваш ответ на вопрос