Unittest setUp / tearDown dla kilku testów


118

Czy jest jakaś funkcja uruchamiana na początku / końcu scenariusza testów? Funkcje setUp i tearDown są uruchamiane przed / po każdym teście.

Zazwyczaj chciałbym mieć to:

class TestSequenceFunctions(unittest.TestCase):

    def setUpScenario(self):
        start() #launched at the beginning, once

    def test_choice(self):
        element = random.choice(self.seq)
        self.assertTrue(element in self.seq)

    def test_sample(self):
        with self.assertRaises(ValueError):
            random.sample(self.seq, 20)
        for element in random.sample(self.seq, 5):
            self.assertTrue(element in self.seq)

    def tearDownScenario(self):
        end() #launched at the end, once

Na razie te setUp i tearDown są testami jednostkowymi i rozprzestrzeniają się we wszystkich moich scenariuszach (zawierających wiele testów), jeden jest pierwszym testem, drugi jest ostatnim testem.


6
Która wersja? Moduł unittest został rozszerzony o moduł module_setup i module_teardown w Pythonie 2.7.
S.Lott,

3
2.7 wprowadził również metody klas setUpClass () i tearDownClass (), które pozwoliłyby ci mieć kilka klas w tym samym pliku z własną konfiguracją dla każdego zestawu i porzuceniem.
Per Fagrell,

Odpowiedzi:


132

Od 2.7 (zgodnie z dokumentacją ) otrzymujesz setUpClassi tearDownClassktóre są wykonywane odpowiednio przed i po uruchomieniu testów w danej klasie. Alternatywnie, jeśli masz ich grupę w jednym pliku, możesz użyć setUpModulei tearDownModule( dokumentacja ).

W przeciwnym razie najprawdopodobniej najlepszym rozwiązaniem będzie utworzenie własnego, pochodnego pakietu TestSuite i zastąpienie go run(). Wszystkie inne wywołania byłyby obsługiwane przez rodzica, a uruchomienie wywoływałoby kod konfiguracji i dezaktywacji wokół wywołania runmetody rodzica .


71

Mam ten sam scenariusz, u mnie metody setUpClass i tearDownClass działają idealnie

import unittest

class Test(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls._connection = createExpensiveConnectionObject()

    @classmethod
    def tearDownClass(cls):
        cls._connection.destroy()

6
Powinno to zostać zaktualizowane, aby było zaakceptowaną odpowiedzią, ponieważ pokazuje poprawny przykład i te funkcje MUSZĄ być metodami klasowymi, aby działały, co nie jest wymienione w zaakceptowanej odpowiedzi.
NuclearPeon

1

W przypadku Pythona 2.5 i podczas pracy z pydevem jest to trochę trudne. Wygląda na to, że pydev nie używa zestawu testów, ale znajduje wszystkie indywidualne przypadki testowe i uruchamia je oddzielnie.

Moim rozwiązaniem było użycie takiej zmiennej klasy:

class TestCase(unittest.TestCase):
    runCount = 0

    def setUpClass(self):
        pass # overridden in actual testcases

    def run(self, result=None):
        if type(self).runCount == 0:
            self.setUpClass()

        super(TestCase, self).run(result)
        type(self).runCount += 1

W przypadku tej sztuczki, gdy dziedziczysz z this TestCase(zamiast z oryginału unittest.TestCase), odziedziczysz również runCountwartość 0. Następnie w metodzie run runCountelement potomnego przypadku testowego jest sprawdzany i zwiększany. To pozostawia runCountzmienną dla tej klasy na 0.

Oznacza to, że setUpClasstest zostanie uruchomiony tylko raz na klasę, a nie raz na instancję.

Nie mam tearDownClassjeszcze metody, ale myślę, że można by coś zrobić używając tego licznika.


0

Oto przykład: 3 metody testowe mają dostęp do udostępnionego zasobu, który jest tworzony raz, a nie na test.

import unittest
import random

class TestSimulateLogistics(unittest.TestCase):

    shared_resource = None

    @classmethod
    def setUpClass(cls):
        cls.shared_resource = random.randint(1, 100)

    @classmethod
    def tearDownClass(cls):
        cls.shared_resource = None

    def test_1(self):
        print('test 1:', self.shared_resource)

    def test_2(self):
        print('test 2:', self.shared_resource)

    def test_3(self):
        print('test 3:', self.shared_resource)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.