Testfall für eine Cachebibliothek

475
edorian

Dies zeigt einen Testfall für eine alte Cache-Bibliothek, die ich für ein Projekt verwende. Es bietet einfache Funktionen zum Speichern / Laden / Löschen (leider statische Aufrufe), aber ich möchte mich auf den Testcode konzentrieren, der für diese Klasse geschrieben wurde.

Meiner Meinung nach sollten die Unit-Tests für eine Klasse zeigen, wie alle Funktionen in der Klasse funktionieren und was von dieser Klasse zu erwarten ist .

Vor kurzem haben wir diese großartige Änderung erhalten, um Code darzustellen. Ich möchte Sie daher fragen, ob Sie diesen Testcode lesen können, um zu verstehen, was die Klasse tun könnte und wie Sie sie verbessern könnten.

<?php

class DatenCacheTest extends PHPUnit_Framework_TestCase {

    function testNothingFound() {
        $this->assertSame(false, DatenCache::load("testNotHereCache"));
    }

    function testSaveLoadSimple() {
        $sDatenSimple = "testStringSaveLoadSimple";
        $sDatenSimpleParam = "testStringParam";
        $sDatenSimpleParam2 = "testStringParam2";
        $sDatenSimpleParam3 = "";
        $sDatenSimpleParam4 = 0;

        $this->assertSame(true, DatenCache::save("testCacheSimple", false, $sDatenSimple));
        $this->assertSame($sDatenSimple, DatenCache::load("testCacheSimple", false));

        $this->assertSame(true, DatenCache::save("testCacheLinearParam", "string", $sDatenSimpleParam));
        $this->assertSame($sDatenSimpleParam, DatenCache::load("testCacheLinearParam", "string"));

        $this->assertSame(true, DatenCache::save("testCacheLinearParam", 5, $sDatenSimpleParam2));
        $this->assertSame($sDatenSimpleParam2, DatenCache::load("testCacheLinearParam", 5));

        $this->assertSame(true, DatenCache::save("testCacheBoundStringParam", false, $sDatenSimpleParam3)); 
        $this->assertSame($sDatenSimpleParam3, DatenCache::load("testCacheBoundStringParam", false));

        $this->assertSame(true, DatenCache::save("testCacheBoundIntParam", false, $sDatenSimpleParam4));
        $this->assertSame($sDatenSimpleParam4, DatenCache::load("testCacheBoundIntParam", false));

        $oObj = new stdClass();
        $oObj->bob = 2;
        $this->assertSame(true,   DatenCache::save("testCacheBoundObjParam", $oObj, "zwei"));
        $this->assertSame("zwei", DatenCache::load("testCacheBoundObjParam", $oObj));
   }

    function testSaveLoadArray() {
        $aDaten = array("da" => "ten", array("ten" => "da"), "Striche" => "' \";s:5:", "h''uh" => "mep", "\\mep\\" => "^^", "Zeilenumbruch" => "\n", "Zeug" => "::}}{:", "'" => '"', '"' => "'");

        $this->assertSame(true, DatenCache::save("testCacheArray", false, $aDaten));
        $this->assertSame($aDaten, DatenCache::load("testCacheArray", false));
    }

    function testSaveLoadExpired() {
        $this->assertSame(true,  DatenCache::save("testCacheExpired", false, "testStringLoadExpired", "-1 seconds"));
        $this->assertSame(false, DatenCache::load("testCacheExpired", false));
    }

    function testSaveLoadObject() {
        $oObj = new stdClass();
        $oObj->bob = 2;
        $this->assertSame(true, DatenCache::save("testCacheBoundIntParam", false, $oObj));

        $oNewObj = DatenCache::load("testCacheBoundIntParam", false);
        $this->assertEquals($oObj, $oNewObj);
        $this->assertSame($oObj->bob, $oNewObj->bob);

    }

    function testSaveLoadComplexParam() {
        $aKonfigEins  = array(DatenCache::ANLAGEN_ID() => 1, DatenCache::SESSION_ID() => "id1");
        $aKonfigZwei  = array(DatenCache::ANLAGEN_ID() => 1, DatenCache::SESSION_ID() => "id2");
        $aKonfigDrei  = array(DatenCache::ANLAGEN_ID() => 1, DatenCache::SESSION_ID() => "id3");
        $aKonfigVier  = array(DatenCache::ANLAGEN_ID() => 1);
        $aKonfigFuenf = array(DatenCache::SESSION_ID() => "id3");
        $aKonfigSechs = array(DatenCache::ANLAGEN_ID() => 1, DatenCache::SESSION_ID() => "id3", DatenCache::PERSON_ID() => 1);

        $this->assertSame(true, DatenCache::save("testCacheComplexParam", $aKonfigEins, "v1"));
        $this->assertSame("v1", DatenCache::load("testCacheComplexParam", $aKonfigEins));
        $this->assertSame(true, DatenCache::save("testCacheComplexParam", $aKonfigZwei, "v2"));
        $this->assertSame("v2", DatenCache::load("testCacheComplexParam", $aKonfigZwei));

        $this->assertSame(false, DatenCache::load("testCacheComplexParam", $aKonfigDrei));
        $this->assertSame(false, DatenCache::load("testCacheComplexParam", $aKonfigVier));
        $this->assertSame(false, DatenCache::load("testCacheComplexParam", $aKonfigFuenf));
        $this->assertSame(false, DatenCache::load("testCacheComplexParam", $aKonfigSechs));

    }

    function testInvalidate() {
        $this->assertSame(true, DatenCache::save("testCacheSimple", false, "testStringInvalidate"));
        DatenCache::invalidate("testCacheSimple");
        $this->assertSame(false, DatenCache::load("testCacheSimple", false));
    }

    function testInvalidateWithParams() {
        $sTestStringEins = "testStringInvalidateWithParams";
        $sTestStringZwei = "testStringInvalidateWithParamsZwei";
        $aKonfigEins = array(DatenCache::ANLAGEN_ID() => 1, "Pony" => false);
        $aKonfigZwei = array(DatenCache::ANLAGEN_ID() => 1, "Pony" => true);

        $this->assertSame(true, DatenCache::save("testCacheInvalidateWithParams", $aKonfigEins, $sTestStringEins));
        $this->assertSame(true, DatenCache::save("testCacheInvalidateWithParams", $aKonfigZwei, $sTestStringEins));
        DatenCache::invalidate("testCacheInvalidateWithParams", $aKonfigEins);
        $this->assertSame(false, DatenCache::load("testCacheInvalidateWithParams", $aKonfigEins));
        $this->assertSame($sTestStringEins, DatenCache::load("testCacheInvalidateWithParams", $aKonfigZwei));


        $aKonfigDrei = array(DatenCache::ANLAGEN_ID() => 1, DatenCache::BENUTZER_ID() => 123, "bob" => "please");
        $aKonfigVier = array(DatenCache::ANLAGEN_ID() => 2, "Pony" => true, "bob" => "please");
        $aPartEins   = array(DatenCache::ANLAGEN_ID() => 1);
        $aPartZwei   = array(DatenCache::BENUTZER_ID() => 123);
        $aPartDrei   = array("bob"  => "please");

        $this->assertSame(true,  DatenCache::save("testCacheInvalidateWithParams", $aKonfigDrei, $sTestStringZwei."1"));
        DatenCache::invalidate("testCacheInvalidateWithParams", $aPartEins);
        $this->assertSame(false, DatenCache::load("testCacheInvalidateWithParams", $aKonfigDrei));

        $this->assertSame(true,  DatenCache::save("testCacheInvalidateWithParams", $aKonfigDrei, $sTestStringZwei."2"));      
        DatenCache::invalidate("testCacheInvalidateWithParams", $aPartZwei);
        $this->assertSame(false, DatenCache::load("testCacheInvalidateWithParams", $aKonfigDrei));

        $this->assertSame(true,  DatenCache::save("testCacheInvalidateWithParams", $aKonfigDrei, $sTestStringZwei."3"));
        DatenCache::invalidate("testCacheInvalidateWithParams", $aPartDrei);
        $this->assertSame(false, DatenCache::load("testCacheInvalidateWithParams", $aKonfigDrei));



        $this->assertSame(true,  DatenCache::save("testCacheInvalidateWithParams", $aKonfigEins, $sTestStringEins));
        $this->assertSame(true,  DatenCache::save("testCacheInvalidateWithParams", $aKonfigZwei, $sTestStringEins));
        $this->assertSame(true,  DatenCache::save("testCacheInvalidateWithParams", $aKonfigDrei, $sTestStringEins));
        DatenCache::invalidate("testCacheInvalidateWithParams", array(DatenCache::ANLAGEN_ID() => 1));
        $this->assertSame(false, DatenCache::load("testCacheInvalidateWithParams", $aKonfigEins));
        $this->assertSame(false, DatenCache::load("testCacheInvalidateWithParams", $aKonfigZwei));
        $this->assertSame(false, DatenCache::load("testCacheInvalidateWithParams", $aKonfigDrei));

        $this->assertSame(true,  DatenCache::save("testCacheInvalidateWithParams", $aKonfigEins, $sTestStringEins));
        $this->assertSame(true,  DatenCache::save("testCacheInvalidateWithParams", $aKonfigVier, $sTestStringEins));
        DatenCache::invalidate("testCacheInvalidateWithParams", array(DatenCache::ANLAGEN_ID() => 1));
        $this->assertSame(false, DatenCache::load("testCacheInvalidateWithParams", $aKonfigEins));
        $this->assertSame($sTestStringEins, DatenCache::load("testCacheInvalidateWithParams", $aKonfigVier));

    }

    function testCleanup() {
        $this->assertSame(true, DatenCache::save("testCacheSimple",       false, "testString", "-5 seconds"));
        $this->assertSame(true, DatenCache::save("testCacheSimpleBleibt", false, "testString", "+30 seconds"));
        DatenCache::cleanup();
        $this->assertSame("testString", DatenCache::load("testCacheSimpleBleibt", false));
        $this->assertSame(false, DatenCache::load("testCacheSimple", false));
        // Direkt auf der DB Prüfen ob der Datensatz wiklich gelöscht wurde und nicht nur ausgelaufen ist
        $this->assertSame(
            array(),
            McDb::getConnection(DB_MC_CACHES)->getRow(
                "SELECT * FROM mc_caches.T_DATEN_CACHE WHERE PARAMETER = ? AND VALUE = ?", "NAME", "testCacheSimple"
            )
        );

    }

    function testCleanupWithParam() {
        $aKonfig = array(DatenCache::ANLAGEN_ID() => 1);
        $this->assertSame(true, DatenCache::save("testCacheSimple", $aKonfig, "testString", "+120 seconds"));
        DatenCache::cleanup();
        $this->assertSame("testString", DatenCache::load("testCacheSimple", $aKonfig));
    }

    function testInvalidateByParam() {
        $mValue1 = 1;
        $mValue2 = 2;
        $aKonfigEins = array(DatenCache::ANLAGEN_ID() => $mValue1);
        $aKonfigZwei = array(DatenCache::ANLAGEN_ID() => $mValue2);

        $this->assertSame(true, DatenCache::save("testCacheInvalidateByParam",  $aKonfigEins, "testString"));
        $this->assertSame(true, DatenCache::save("testCacheInvalidateByParam2", $aKonfigZwei, "testString2"));

        DatenCache::invalidateByParam(DatenCache::ANLAGEN_ID());

        $this->assertSame(false, DatenCache::load("testCacheInvalidateByParam",  $aKonfigEins));
        $this->assertSame(false, DatenCache::load("testCacheInvalidateByParam2", $aKonfigZwei));


        $this->assertSame(true, DatenCache::save("testCacheSimple",  $aKonfigEins, "testString"));
        $this->assertSame(true, DatenCache::save("testCacheSimple2", $aKonfigZwei, "testString2"));

        DatenCache::invalidateByParam(DatenCache::ANLAGEN_ID(), $mValue1);

        $this->assertSame(false, DatenCache::load("testCacheSimple",  $aKonfigEins));
        $this->assertSame("testString2", DatenCache::load("testCacheSimple2", $aKonfigZwei));
    }

    function testInvalidateByParamLike() {
        $mValue1 = "I wan't a Pony";
        $mValue2 = "No Pony for you !";
        $mValue3 = "xxx";

        $this->assertSame(true, DatenCache::save("PonyCache", array("PonyParam" => $mValue1), "test1"));
        $this->assertSame(true, DatenCache::save("PonyCache", array("PonyParam" => $mValue2), "test2"));
        $this->assertSame(true, DatenCache::save("PonyCache", array("PonyParam" => $mValue3), "test3"));

        DatenCache::invalidateByParam("PonyParam", "%Pony%", true);

        $this->assertSame(false,   DatenCache::load("PonyCache", array("PonyParam" => $mValue1)));
        $this->assertSame(false,   DatenCache::load("PonyCache", array("PonyParam" => $mValue2)));
        $this->assertSame("test3", DatenCache::load("PonyCache", array("PonyParam" => $mValue3)));
    }

    /**
     * @expectedException PHPUnit_Framework_Error
     */
    function testInvalidSaveTime() {
        $this->assertSame(false, DatenCache::save("testFail", null, "test1", "invalidStrtotime"));
    }

    function testInvalidSaveTimeReturn() {
        $this->assertSame(false, @DatenCache::save("testFail", null, "test1", "invalidStrtotime"));
    }
}
Antworten
12
Das sieht aus wie die Version von Stack Overflow mit langen Fragen Carlos Muñoz vor 10 Jahren 0

4 Antworten auf die Frage

7
indyK1ng

Abgesehen von langen Zeilen sehe ich nichts zu Unlesbares. Ich empfehle nicht, Funktionsnamen zu kürzen, da dadurch die Funktionsweise der Funktion weniger klar wird. Versuchen Sie stattdessen, die als Parameter übergebenen Funktionsaufrufe auf verschiedene Zeilen aufzuteilen, indem Sie die Zeile entweder über mehrere Zeilen aufteilen oder den zurückgegebenen Wert als Variable speichern und diese Variable übergeben.

7
Eric Bréchemier

Sie sollten die optionale Zeichenfolgenachricht als letztes Argument für Assertionsaufrufe angeben. dreh dich um:

$this->assertSame(true, DatenCache::save("testCacheSimple", false, $sDatenSimple));

Das sehr gut finden:

$this->assertSame(
  true,
  DatenCache::save("testCacheSimple", false, $sDatenSimple),
                                      "a successful [describe operation] ".
                                   "is expected for [describe arguments]");

Dieses Formular erinnert mich daran, dass Perl-Anweisungen etwas tun oder die "Nachricht" tun, und ich verwende die Einrückung, wobei ich die Nachricht bei Bedarf rechtsbündig in einer separaten Zeile halte, um sie in die richtige Perspektive zu bringen:

assert( something,                                   "something expected");
assert( something else,                         "something else expected");
assert( something long
        that spans multiple lines,
                                                         "something long ".
                                     "that spans multiple lines expected");

Auf diese Weise werden alle Nachrichten auf der rechten Seite ausgerichtet und können separat gelesen werden.

Sie sollten auch die spezifischste Assertion verwenden, anstatt ständig assertSame () zu verwenden. Beim Vergleich mit true würde stattdessen die Verwendung von assertTrue () die Absicht klarstellen.

6
Pete 007

IMHO, ähnlich wie beim Schreiben einer Klasse sollte eine einzige Methode eine Sache tun und diese eine Sache gut machen.

Sie sollten weniger Assertions pro Funktion in Ihrer Testklasse durchführen, vorzugsweise 1 Assertion pro Funktion .

In der Regel gilt: Je weniger Codezeilen in einer Testfunktion, desto besser ist der Test.

Auf diese Weise können Sie einen Test eines Verwendungsbeispiels für jedes Funktions- und Assertionspaar dokumentieren, und in der Tat erstellen Sie eine Verwendungsdokumentation für die zu testende Klasse.

Edit: Ich habe gerade nach einem weiteren Blick auf Ihren Test bemerkt, dass Sie zwei Funktionen in vielen Tests testen (laden und speichern). Diese sollten einzeln getestet werden, da sich das eine auf das andere auswirken kann und unvorhersehbare Ergebnisse erzielen kann.

Einfach = robust

Ich kenne die Klasse offensichtlich nicht, aber ich vermute, dass Sie ähnliche Tests schreiben sollten. Isolieren der getesteten Methoden und Aufteilen der Tests in kleinere Einheiten. Hoffentlich hilft dir das.

<?php
// Instead of $this->assertSame() use $this->assertTrue() when testing for true.
// much easier to see what outcome is needed from test.

class DatenCacheTest extends PHPUnit_Framework_TestCase {

function setup(){
    // runs before every test like __construct() in a class.
    $this->str = 'testString';
}

function tearDown(){
    // runs after every test like __destruct() in a class.
}

function testSaveSimple(){
    $this->assertTrue( DatenCache::save("testCacheSimple", false, $this->str) );
}

function testSaveLinearParam(){
    $this->assertTrue( DatenCache::save("testCacheLinearParam", "string", $this->str) );
}

function testSaveBoundObjParam(){
    $oObj = new stdClass();
    $oObj->bob = 2;
    $this->assertTrue( DatenCache::save("testCacheBoundObjParam", $oObj, "zwei") );
}
// complete tests for all aspects of DatenCache::save()

// Test DatenCache::load() because DatenCache::save() has been tested.
function testLoadSimple(){
    DatenCache::save("testCacheSimple", false, $this->str);
    $this->assertSame( $this->str, DatenCache::load($this->str, false) );
}

function testLoadNoCache(){
    $this->assertFalse( DatenCache::load("testNoCache") );
}
Ich stimme dem zu. Sie können auch @covers in den Docblocks verwenden, um sicherzustellen, dass Ihre Testabdeckung nicht überschätzt wird und dass jeder Test nur die Methode abdeckt, die er zu testen versucht. Paul vor 8 Jahren 0
3
TryPyPy

Mir fehlt das Syntaxwissen, um zu sagen, dass ich die Klasse verstehe. Ich kann sagen, dass das Lesen etwas schwierig ist, da lange Zeilen verwendet werden und die dominanten Muster repetitive Methoden- / Variablennamen sind. Testnamen sind ausreichend beschreibend

Wenn Sie könnten vielleicht Methoden extrahieren wie DatenCache::loadauf Dloadund $this->assertSamezu, aSamees würde weniger beschäftigt erhalten. Oder machen Sie eine Utility-Funktion, da Sie die Gleichheit von Booleans behaupten (so assertTrueund assertFalsekönnte sie klarer machen). Wenn möglich, können auch Arrays außerhalb der Aufrufe erstellt werden.