PHPUnit: Wie erstelle ich eine Funktion, die einmal für alle Tests in einer Klasse aufgerufen wird?

Lesezeit: 7 Minuten

Benutzer-Avatar
Schlange

Ich habe eine PHPUnit-Testfallklasse (bestehend aus einigen Testfunktionen). Ich möchte eine schreiben oneTimeSetUp() Funktion einmal für alle meine Tests in der Klasse aufgerufen werden (im Gegensatz zur Standard setUp() Funktion, die für jeden Test in der Klasse einmal aufgerufen wird). Mit anderen Worten, ich suche nach einem PHPUnit-Äquivalent zum JUnit @BeforeClass Anmerkung.

Gleiche Frage mit a oneTimeTearDown() Funktion.

Ist dies in PHPUnit möglich?

  • Ich verstehe die Notwendigkeit, dies manchmal für die Leistung zu tun. Es wird empfohlen, dies nach Möglichkeit zu vermeiden, damit Sie den Status nicht zwischen Tests teilen.

    – Gregor K

    23. August 2011 um 10:33 Uhr

  • @Greg: Ich stimme zu. Dennoch gibt es Situationen, in denen es besser ist, alle Tests einmal zu initialisieren (um beispielsweise eine Verbindung zur db herzustellen).

    – Schlange

    23. August 2011 um 12:19 Uhr

  • Ich versuche zu vermeiden, dass ein DB-Server benötigt wird, indem ich den Zend_Db / PDO-Adapter in meinem Datamapper verspotte, dann führe ich Behauptungen auf dem SQL aus, das meine Klassen produzieren. Ich weiß es zu schätzen, dass es manchmal für Funktions- / End-to-End-Tests unvermeidlich ist.

    – Gregor K

    23. August 2011 um 19:50 Uhr

  • @Greg: Die Tests, an denen ich arbeite, sind Funktionstests. Sie prüfen die höchste Ebene, das Endprodukt.

    – Schlange

    24. August 2011 um 7:26 Uhr

Benutzer-Avatar
langweilig

Schauen Sie sich an setUpBeforeClass() aus Abschnitt 6 der PHPUnit-Dokumentation.

Für das einmalige TearDown sollten Sie verwenden tearDownAfterClass();.

Beide Methoden sollten in Ihrer Klasse als statische Methoden definiert werden.

  • Ich wollte gerade dasselbe schreiben … Ihre Antwort ist DIE Antwort

    – Fabio

    23. August 2011 um 9:44 Uhr


  • Gibt es eine nicht statische Alternative?

    – Martijn

    9. Juni 2016 um 9:49 Uhr

  • @Martijn leider gibt es dafür derzeit keine Methode in phpunit. Glücklicherweise können Sie diese fehlende Funktion überschreiben, indem Sie ein “initialisiertes” Flag oder Lazy Loading in setUp() verwenden. Es wird immer noch vor jedem Test ausgeführt, tut aber nichts, wenn die Testklasse bereits initialisiert wurde.

    – Konrad Gałęzowski

    4. Januar 2017 um 21:01 Uhr

  • Zum setUpFechten mit einer Fahne initialized funktioniert, aber nicht für tearDown weil du nicht weißt, welches der letzte Test ist.

    – olidem

    8. November 2018 um 22:15 Uhr

  • Beachten Sie, dass dies nur funktioniert, wenn processIsolation in XML oder Parametern nicht wahr ist. Gibt es also eine andere Option für setupBeforeClass() ?

    – Apolinux

    28. Mai 2020 um 21:57 Uhr

Benutzer-Avatar
Däne Powell

setUpBeforeClass() Dies ist der Weg, dies zu tun, wenn alle Ihre Tests buchstäblich in einer einzigen Klasse enthalten sind.

Ihre Frage impliziert jedoch, dass Sie Ihre Testklasse möglicherweise als Basisklasse für mehrere Testklassen verwenden. In diesem Fall wird vor jeder setUpBeforeClass ausgeführt. Wenn Sie es nur einmal ausführen möchten, können Sie es mit einer statischen Variablen schützen:

abstract class TestBase extends TestCase {

  protected static $initialized = FALSE;
  
  public function setUp() {
    
    parent::setUp();

    if (!self::$initialized) {
      // Do something once here for _all_ test subclasses.
      self::$initialized = TRUE;
    }
  }

}

Eine letzte Möglichkeit wäre a Hörer testen.

  • Dies war hilfreich, aber denken Sie daran, es hinzuzufügen parent::setUp(); als erste Zeile der public function setUp().

    – Ryan

    27. August 2019 um 15:49 Uhr

  • Das habe ich 2 Tage vor dir gesagt und irgendwie bekommst du all die positiven Stimmen. Ich wundere mich warum.

    – vgl

    21. April 2020 um 2:52 Uhr

  • @cprn Weil Betreuer nicht gerne verwenden @before Kommentarweg oder irgendetwas, das den Codefluss in Kommentaren verbirgt.

    – Top-Master

    15. Mai um 16:30 Uhr

  • @Top-Master Ja, ich glaube nicht, dass das der Grund ist – mein Beispiel enthielt früher setUp() sowie vor Bearbeitungen. Es gibt eine Menge Leute, die ihren SO-Content mit gefälschten Konten verbessern, bevor sie einen Lebenslauf oder ein Vorstellungsgespräch senden. AFAIR, das war mein Verdacht damals. Heutzutage ist es mir völlig egal.

    – vgl

    8. Juni um 0:09

  • @cprn Jetzt verstehe ich dich: 1. jemand hat deine Antwort kopiert 2. und anstatt dass diese “Kopie” vom Moderator gelöscht wurde, hat er sogar mehr Upvotes bekommen 3. Schließlich warst du gezwungen zu bearbeiten, um zu vermeiden, ein Duplikat zu sein (obwohl du warst der erste, der geantwortet hat).

    – Top-Master

    8. Juni um 2:50

Ich bin mit derselben Frage auf diese Seite gekommen, aber die akzeptierte Antwort wird in allen Klassen ausgeführt und war für mich nicht die richtige Antwort.

Wenn Sie wie ich sind, besteht Ihr erster “Integrationstest” darin, die DB zu löschen und Migrationen durchzuführen. Dadurch erhalten Sie eine Datenbank-Basislinie für alle Tests. Ich ändere zu diesem Zeitpunkt ständig Migrationsdateien, daher ist das Einrichten der Baseline wirklich Teil aller Tests.

Die Migration dauert eine Weile, daher möchte ich nicht, dass sie bei allen Tests ausgeführt wird.

Dann musste ich die Datenbank aufbauen und jedes Stück testen. Ich muss einen Bestelltest schreiben, aber zuerst muss ich einige Produkte erstellen und testen, dann muss ich eine Importfunktion testen.

Also, was ich getan habe, ist SUPER einfach, aber im Internet nicht sehr gut erklärt. Ich habe einen einfachen Test erstellt, um die Datenbank einzurichten. Fügen Sie dann in Ihrer phpspec.xml-Datei eine Testsuite hinzu….

<testsuite name="Products">
    <file>tests/in/SystemSetupTest.php</file>
    <file>tests/in/ProductTest.php</file>
    <file>tests/in/ProductImportTest.php</file>
</testsuite>

Und in der SystemSetupTest.php ….

class SystemSetupTest extends ApiTester
{

    /** @test */
    function system_init()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
        self::createEM(); //this has all the code to init the system...
    }
}

Führen Sie es dann wie folgt aus:

phpunit –testsuite Produkte

Am Ende ist es viel einfacher. Es wird mir erlauben, mein System richtig aufzubauen.

Zusätzlich verwende ich Laravel 5. Bei der Verwendung setUpBeforeClass() Am Ende habe ich Bootstrap-Probleme, die ich sicher beheben kann, aber die Methode, die ich oben verwende, funktioniert perfekt.

  • Besser als das, führen Sie Tests wie folgt durch: ./artisan migrate --datebase CONNECTION_NAME && ./vendor/bin/phpunit. Keine große Sache, wenn Sie den Befehlsverlauf Ihrer Shell verwenden.

    – x-yuri

    28. November 2016 um 20:36 Uhr


  • @x-yuri wie kommt es, Kumpel? Wenn Sie es lokal mit dem DatabaseRefresh-Merkmal ausführen, töten Sie zuerst Ihre lokale Datenbank. Das lokale Ausführen von artisan würde auf der lokalen .env-Datei ausgeführt, dann würden die Komponententests auf test db ausgeführt, da es in phpunit.xml als Testing env gekennzeichnet ist, mit allen Konsequenzen, dieser Ansatz ist nicht nachhaltig. Die Bootstrap-Datei ist der richtige Ort, um Ihren benutzerdefinierten Code einzuschließen, der vor allen Tests ausgeführt werden soll. Der Migrations-Seed ist der perfekte Kandidat für Bootstrap.

    – Valentin Rusk

    31. August um 11:49 Uhr


  • @ValentinRusk Ich habe Laravel seit einiger Zeit nicht mehr verwendet, aber anscheinend war meine Idee, dass Sie die Datenbank migrieren können, anstatt einen Test zu erstellen, der die Datenbank migriert, bevor Sie die Tests ausführen. Niemand schlägt vor, die lokale Datenbank zu beenden. Hast du das bemerkt --database Schalter? Was macht DatabaseRefresh zu tun haben mit ./artisan migrate?.. Und es gibt eine Reihe von Möglichkeiten, die Migration der Datenbank (npm run test, ./test, make test, …). Wenn es einen Weg gibt phpunit Migrieren Sie die DB einmal, das wäre ein besserer Weg. Aber was ich getan habe, ist eine (aus meiner Sicht) bessere Lösung als die in der Antwort.

    – x-yuri

    Vor 2 Tagen

  • Es ist auch nicht klar, ob der Autor nur Migration vorschlägt (SystemSetupTest.php) oder auch das Hinzufügen von Daten zur Datenbank. Wenn beides der Fall ist, gefällt mir die Idee nicht wirklich, kann aber nicht ausschließen, dass es in manchen Fällen Sinn machen könnte.

    – x-yuri

    Vor 2 Tagen

Das bootstrap Option kann in diesen Fällen verwendet werden.

Sie können es von der Befehlszeile aus aufrufen

phpunit --bootstrap myBootstrap.php

Oder fügen Sie es wie folgt in die XML-Datei ein:

<phpunit bootstrap="myBootstrap.php">
...
</phpunit>

Benutzer-Avatar
cprn

Erweiterung der akzeptierten Antwort:

Keiner dieser setUpBeforeClass(), tearDownAfterClass(), @beforeClass, @afterClass läuft im Objektkontext (statische Methoden). Sie können diese Einschränkung umgehen, indem Sie alle schützen @before Code stattdessen mit einer statischen Eigenschaft wie folgt:

class MyTest extends PHPUnit\Framework\TestCase
{
    private static $ready = false;

    /**
     * @before
     */
    protected function firstSetUp()
    {
        if (static::$ready))
            return;

        /* your one time setUp here */

        static::$ready = true;
    }
}

Es kann nicht verwendet werden @afterda man nicht sagen kann, wann der letzte Test aufgerufen wurde.

1353390cookie-checkPHPUnit: Wie erstelle ich eine Funktion, die einmal für alle Tests in einer Klasse aufgerufen wird?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy