Кэширование результата setUp () с использованием Python unittest - PullRequest
9 голосов
/ 31 декабря 2008

В настоящее время у меня есть unittest.TestCase, который выглядит как ..

class test_appletrailer(unittest.TestCase):
    def setup(self):
        self.all_trailers = Trailers(res = "720", verbose = True)

    def test_has_trailers(self):
        self.failUnless(len(self.all_trailers) > 1)

    # ..more tests..

Это работает нормально, но вызов Trailers() занимает около 2 секунд. Учитывая, что setUp() вызывается перед каждым тестом, тесты теперь выполняются почти 10 секунд (только с 3 функциями теста)

Как правильно кэшировать переменную self.all_trailers между тестами?

Удаление функции setUp и выполнение ..

class test_appletrailer(unittest.TestCase):
    all_trailers = Trailers(res = "720", verbose = True)

.. работает, но затем он утверждает, что «Выполнил 3 теста за 0,000 с», что неверно. Единственный другой способ, о котором я мог подумать, это иметь глобальную переменную cache_trailers (которая работает правильно, но довольно ужасно):

cache_trailers = None
class test_appletrailer(unittest.TestCase):
    def setUp(self):
        global cache_trailers
        if cache_trailers is None:
            cache_trailers = self.all_trailers = all_trailers = Trailers(res = "720", verbose = True)
        else:
            self.all_trailers = cache_trailers

Ответы [ 5 ]

14 голосов
/ 31 декабря 2008

Как насчет использования члена класса, который инициализируется только один раз?

class test_appletrailer(unittest.TestCase):

    all_trailers = None

    def setup(self):
        # Only initialize all_trailers once.
        if self.all_trailers is None:
            self.__class__.all_trailers = Trailers(res = "720", verbose = True)

Поиск, который ссылается на self.all_trailers, перейдет к следующему шагу в MRO - self.__class__.all_trailers, который будет инициализирован.

8 голосов
/ 31 декабря 2008

Альтернативой предлагаемому решению будет использование более функционального тестера, такого как Nose . С Nose вы можете иметь функции настройки на уровне модулей, которые будут запускаться один раз для тестового модуля. Поскольку он полностью совместим с unittest, вам не нужно менять код.

Из руководства по носу:

носовые опоры на упаковке, модуль, класс и уровень тестового набора, так дорогая инициализация может быть сделана как можно реже .

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

5 голосов
/ 04 апреля 2011

Если вы используете Python> = 2.7, вы можете использовать метод setUpClass, который вызывается только один раз для всего модульного теста.

import unittest

from trailers import Trailers

class AppleTrailerTestCase(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        # only initialize all_trailers once
        cls.all_trailers = Trailers(res='720', verbose=True)

    @classmethod
    def tearDownClass(cls):
        # drop the reference explicitly to let the Trailers object be garbage
        # collected
        cls.all_trailers = None

    def test_one(self):
        # ...

    def test_two(self):
        # ...
1 голос
/ 31 декабря 2008

Что делает класс Trailers?
Если он удерживает какое-то состояние, то у вас есть для его сброса каждый раз, когда выполняется модульный тест.

Чтобы решить вашу проблему, я бы использовал фиктивный объект - просто эмулирующий интерфейс трейлеров, предоставляющий поддельный набор данных.


Обновление : поскольку трейлеры только читают данные XML, я бы выбрал решение, подобное предложенному cdleary.

0 голосов
/ 02 января 2011

Стоит отметить, что в течение 2010 года тестовый прогон, используемый в мире Zope / Plone, был выпущен как отдельный модуль, что неудивительно называется zope.testrunner . Он поддерживает настройки кэширования в виде «слоев». Проверьте это.

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