Каков правильный способ сообщить об ошибке в unittest Python в методе установки?

Я прочитал несколько противоречивых советов по использованию assert на setUp метод модульного теста Python. Я не вижу вреда в провале теста, если предварительное условие, на которое опирается тест, терпит неудачу.

например:

import unittest

class MyProcessor():
    """
    This is the class under test
    """

    def __init__(self):
        pass

    def ProcessData(self, content):
        return ['some','processed','data','from','content'] # Imagine this could actually pass

class Test_test2(unittest.TestCase):

    def LoadContentFromTestFile(self):
        return None # Imagine this is actually doing something that could pass.

    def setUp(self):
        self.content = self.LoadContentFromTestFile()
        self.assertIsNotNone(self.content, "Failed to load test data")
        self.processor = MyProcessor()

    def test_ProcessData(self):
        results = self.processor.ProcessData(self.content)
        self.assertGreater(results, 0, "No results returned")

if __name__ == '__main__':
    unittest.main()

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

F
======================================================================
FAIL: test_ProcessData (__main__.Test_test2)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:ProjectsExperimentstest2.py", line 21, in setUp
    self.assertIsNotNone(self.content, "Failed to load test data")
AssertionError: unexpectedly None : Failed to load test data

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)

5 ответов


цель setUp уменьшить шаблонный код который создает между тестами в тестовом классе на этапе упорядочения.

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

исходя из вышеизложенного, вы не должны ничего утверждать в своем setUp метод.

Итак, как упоминалось ранее; если вы не можете создать тестовый условие, то тест испорчен.Искусство Модульного Тестирования ( для полного раскрытия Лиор Фридман (он был боссом Роя) - мой друг, и я работал в тесном контакте с ними более 2 лет, поэтому я немного предвзят...)

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

вернемся к вашему примеру; есть шаблон для структурирования тестов, где вам нужно загрузить внешний ресурс(для всех/большинства из них). Просто Примечание; прежде чем вы решите применить этот шаблон, убедитесь, что вы не можете иметь этот контент в качестве статического ресурса в классе вашего UT, если другим тестовым классам нужно использовать этот ресурс, извлеките этот ресурс в модуль.

следующий шаблон уменьшает вероятность сбоя, так как у вас меньше вызовов внешнего ресурса:

class TestClass(unittest.TestCase):

    def setUpClass(self):
        # since external resources such as other servers can provide a bad content
        # you can verify that the content is valid
        # then prevent from the tests to run  
        # however, in most cases you shouldn't.
        self.externalResourceContent = loadContentFromExternalResource()


    def setUp(self):
        self.content = self.copyContentForTest()

плюсы:

  1. меньше шансов на провал
  2. предотвращение поведения несогласованности (1. что-то / one отредактировало внешний ресурс. 2. вам не удалось загрузить внешний ресурс в некоторых тестах)
  3. быстрое исполнение

плюсы:

  1. код более сложный

setUp не утверждения предварительные условия, но создания них. Если ваш тест не может создать необходимое приспособление, то он сломленн, не терпя неудачу.


с Документация Стандартной Библиотеки Python:

"если метод Setup() вызывает исключение во время выполнения теста, фреймворк будет считать, что тест потерпел ошибку, и метод runTest() не будет выполняться. Если setUp() удалось, метод tearDown () будет запущен независимо от того, удалось runTest () или нет. Такие рабочая среда для кода тестирования называется креплением."

исключение утверждения в метод setUp () будет рассматриваться как ошибка unittest framework. Тест не будет выполнен.


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

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

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

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

также ничто не мешает вам определять методы для выполнения общих проверок в unittest классе и вызывать их в setUp или в test_methods, это может помочь сохранить сложность в определенных и управляемые районы.

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

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


есть одна причина, по которой вы хотите избежать утверждений в setUp(). Если установка не удается, ваш tearDown будет не быть казнен.

если вы настроили набор записей базы данных, например, и ваш демонтаж удаляет эти записи, то эти записи не будут удалены.

этот фрагмент:

import unittest

class Test_test2(unittest.TestCase):

    def setUp(self):
        print 'setup'
        assert False

    def test_ProcessData(self):
        print 'testing'

    def tearDown(self):
        print 'teardown'

if __name__ == '__main__':
    unittest.main()

запустить setUp():

$ python t.py 
setup
E
======================================================================
ERROR: test_ProcessData (__main__.Test_test2)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "t.py", line 7, in setUp
    assert False
AssertionError

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)