Запустити setUp лише один раз для набору автоматизованих тестів


81

Моя версія Python - 2.6.

Я хотів би виконати метод набору тестів лише один раз, оскільки я роблю там те, що потрібно для всіх тестів.

Моя ідея полягала в тому, щоб створити логічну змінну, для якої після першого виконання буде встановлено значення "true", а потім відключити більше одного виклику методу установки.

class mySelTest(unittest.TestCase):
    setup_done = False

    def setUp(self):
        print str(self.setup_done)
            
        if self.setup_done:
            return
        self.setup_done = True
        print str(self.setup_done)

Вихід:

False

True

--- Test 1 ---

False

True

--- Test 2 ---

чому це не працює? Я щось пропустив?


6
Unittest створює окремі екземпляри для кожного тесту
Девід Робінсон

2
Не роби цього. Впровадити якийсь інший механізм. Але не намагайтеся змінити значення setUp.
Девід Хеффернан

Відповіді:


114

Ви можете використовувати setUpClassдля визначення методів, які запускаються лише один раз на тестування.


Дякуємо за Ваш відповідь. Оскільки я використовую Python 2.6.6, setUpClass недоступний.
Кесандал

2
@JohnM .: Ви можете завантажити пакет backtest unittest2 і отримати все нове на своєму старому python-dist.
Macke

Питання стосується Python 2, але оскільки відповідь також діє для Python 3, я змінив URL-адресу, оскільки Python 2 застарілий.
CharlesB

66

Відповідь Даніеля є правильною, але ось приклад, щоб уникнути деяких типових помилок, які я знайшов, наприклад, не звернення super()до, setUpClass()коли TestCaseє підкласом unittest.TestCase(наприклад, в django.testабо falcon.testing).

У документації для setUpClass()не згадується, що вам потрібно телефонувати super()у таких випадках. Якщо цього не сталося, ви отримаєте повідомлення про помилку, як видно з цього відповідного запитання .

class SomeTest(TestCase):
    def setUp(self):
        self.user1 = UserProfile.objects.create_user(resource=SomeTest.the_resource)

    @classmethod
    def setUpClass(cls):
        """ get_some_resource() is slow, to avoid calling it for each test use setUpClass()
            and store the result as class variable
        """
        super(SomeTest, cls).setUpClass()
        cls.the_resource = get_some_resource()

1
Зауважте, що це актуально лише тоді, коли TestCaseє підкласом unittest.TestCase.
EliadL

3

Якщо ви опинилися тут через необхідність завантажити деякі дані для тестування ... тоді, наскільки ви використовуєте Django 1.9+, будь ласка, перейдіть за setUpTestData :

class MyTests(TestCase):

    @classmethod
    def setUpTestData(cls):
        # Set up data for the whole TestCase
        cls.foo = Foo.objects.create(bar="Test")

    def test1(self):
        self.assertEqual(self.foo.bar, 'Test') 

2

Не намагайтеся виводити дзвінки на setUp, просто зателефонуйте йому один раз.

Наприклад:

class MyClass(object):
    ...

def _set_up():
    code to do one-time setup

_set_up()

Це викличе _set_up () при першому завантаженні модуля. Я визначив, що це функція на рівні модуля, але ви в рівній мірі можете зробити це методом класу MyClass.


2

Помістіть весь код, який потрібно налаштувати, один раз за межами mySelTest.

setup_done = False

class mySelTest(unittest.TestCase):

    def setUp(self):
        print str(setup_done)

        if setup_done:
            return

        setup_done = True
        print str(setup_done)

Інша можливість полягає у створенні вами екземпляра класу Singleton setUp(), який запустить __new__код лише один раз і поверне екземпляр об’єкта для решти викликів. Дивіться: Чи існує простий, елегантний спосіб визначити одинаків?

class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(
                            cls, *args, **kwargs)
            # PUT YOUR SETUP ONCE CODE HERE!
            cls.setUpBool = True

        return cls._instance

class mySelTest(unittest.TestCase):

    def setUp(self):
        # The first call initializes singleton, ever additional call returns the instantiated reference.
        print(Singleton().setUpBool)

Ваш спосіб теж працює.


2

setup_done - це змінна класу, а не змінна екземпляра.

Ви посилаєтесь на неї як змінну екземпляра:

self.setup_done

Але вам потрібно посилатися на неї як змінну класу:

mySelTest.setup_done

Ось виправлений код:

class mySelTest(unittest.TestCase):
    setup_done = False

    def setUp(self):
        print str(mySelTest.setup_done)

        if mySelTest.setup_done:
            return
        mySelTest.setup_done = True
        print str(mySelTest.setup_done)

2

Я використовую Python 3 і виявив, що clsпосилання також доступне в setupметоді, тому працює наступне:

class TestThing(unittest.TestCase):

  @classmethod
  def setUpClass(cls):
    cls.thing = Thing() # the `thing` is only instantiated once

  def setup(self):
    self.thing = cls.thing # ...but set on each test case instance

  def test_the_thing(self):
    self.assertTrue(self.thing is not None)

1
Ви не можете отримати доступ до cls всередині setUp, який є методом екземпляра (нижній регістр setup () не буде викликаний, оскільки це не метод unittest setUp, ані метод, що починається з 'test'), імовірно, тому ви не отримали помилка) Однак, як тільки ви визначите змінні класу в setUpClass, ви можете просто викликати self.thing у всіх методах екземпляра
khuang834

Дякую, @ khuang834. Ти маєш рацію. Це було недогляд з мого боку.
Грег Росс

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.