Führen Sie setUp nur einmal aus, um eine Reihe automatisierter Tests durchzuführen

80

Meine Python-Version ist 2.6.

Ich möchte die Test-SetUp-Methode nur einmal ausführen, da ich dort Dinge mache, die für alle Tests benötigt werden.

Meine Idee war es, eine boolesche Variable zu erstellen, die nach der ersten Ausführung auf 'true' gesetzt wird und dann mehr als einen Aufruf der Setup-Methode deaktiviert.

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)

Die Ausgabe:

False

True

--- Test 1 ---

False

True

--- Test 2 ---

Warum funktioniert das nicht? Habe ich etwas vergessen?

Kesandal
quelle
6
Unittest erstellt separate Instanzen für jeden Test
David Robinson
2
Tu das nicht. Implementieren Sie einen anderen Mechanismus. Aber versuchen Sie nicht, die Bedeutung von zu ändern setUp.
David Heffernan
Mögliches Duplikat von Unittest setUp / tearDown für mehrere Tests
Stevoisiak

Antworten:

113

Sie können setUpClassMethoden definieren, die nur einmal pro Testsuite ausgeführt werden.

Daniel Roseman
quelle
Danke für deine Antwort. Da ich Python 2.6.6 verwende, ist setUpClass nicht verfügbar.
Kesandal
2
@JohnM.: Sie können das unittest2-Backport-Paket herunterladen und alle neuen Inhalte auf Ihrem älteren Python-Dist herunterladen.
Macke
Die Frage befasst sich mit Python 2, aber da die Antwort auch für Python 3 gültig ist, habe ich die URL geändert, da Python 2 veraltet ist.
CharlesB
64

Daniels Antwort ist richtig, aber hier ist ein Beispiel einige häufige Fehler zu vermeiden , fand ich, wie nicht Aufruf super()in , setUpClass()wenn TestCaseeine Unterklasse von unittest.TestCase(wie in django.testoder falcon.testing).

In der Dokumentation für setUpClass()wird nicht erwähnt, dass Sie super()in solchen Fällen anrufen müssen . Andernfalls wird eine Fehlermeldung angezeigt, wie in dieser verwandten Frage dargestellt .

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()
Chemary
quelle
1
Beachten Sie, dass dies nur relevant ist, wenn TestCasees sich um eine Unterklasse von handelt unittest.TestCase.
EliadL
3

Wenn Sie hier gelandet sind, weil Sie einige Daten zum Testen laden müssen ... Wenn Sie Django 1.9+ verwenden, wählen Sie bitte 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') 
Andilabs
quelle
2

Versuchen Sie nicht, die Aufrufe von setUp zu deduplizieren, sondern rufen Sie es einfach einmal auf.

Zum Beispiel:

class MyClass(object):
    ...

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

_set_up()

Dies ruft _set_up () auf, wenn das Modul zum ersten Mal geladen wird. Ich habe es als Funktion auf Modulebene definiert, aber Sie können es auch zu einer Klassenmethode von MyClass machen.

Paul Hankin
quelle
2

Platzieren Sie den gesamten Code, den Sie einrichten möchten, einmal außerhalb von 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)

Eine andere Möglichkeit besteht darin, eine Singleton-Klasse zu haben, in der Sie instanziieren setUp(), die den __new__Code nur einmal ausführt und die Objektinstanz für den Rest der Aufrufe zurückgibt. Siehe: Gibt es eine einfache, elegante Möglichkeit, Singletons zu definieren?

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)

Dein Weg funktioniert aber auch.

NuclearPeon
quelle
2

setup_done ist eine Klassenvariable, keine Instanzvariable.

Sie verweisen auf eine Instanzvariable:

self.setup_done

Sie müssen es jedoch als Klassenvariable referenzieren:

mySelTest.setup_done

Hier ist der korrigierte Code:

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)
Jersey Bohne
quelle
0

Ich verwende Python 3 und habe festgestellt, dass die clsReferenz auch in der setupMethode verfügbar ist. Daher funktioniert Folgendes:

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)
Greg Ross
quelle