Frage

Ich teste einen PHP-Code mit simpleetest und bin in Schwierigkeiten geraten. In meinen Tests einer Datenbankklasse möchte ich in der Lage sein, eine Erwartung für PHPS festzulegen können mysql Funktionen. In meinen Tests einer Wrapper -Klasse für die mail Funktion Ich möchte PHPS verspotten mail Funktion. Dies sind nur einige Beispiele.

Der Punkt ist: Ich möchte nicht (immer) testen, ob meine E-Mail-Klasse eine E-Mail sendet. Ich möchte testen, wie sie das anruft mail Funktion. Ich möchte in der Lage sein, zu steuern, was diese Funktionen zurückkehren. Ich möchte in der Lage sein, meine Datenbankklasse zu testen, ohne eine Datenbank, Geräte und diese ganze Menge zu benötigen.

Ich habe einige Erfahrung mit dem Testen von Ruby Code und test :: unit und rspec es sehr einfach, Code isoliert zu testen. Ich bin neu beim Testen von PHP und es fühlt sich an, als würde ich viel mehr testen, als ich brauchte, um meine Tests zu bestehen.

Gibt es einen Weg in Simpleetest oder Phpunit oder einem anderen Test -Framework, der dies möglich oder einfacher macht?

War es hilfreich?

Lösung

Nicht automatisiert. Was Sie tun können, besteht darin, Ihren Code so zu schreiben, dass externe Abhängigkeiten in Objekte eingewickelt werden, die von außen eingegeben werden. In Ihrer Produktionsumgebung werden Sie einfach die realen Adapter verdrahten, aber während des Tests können Sie sie mit Stubs oder Mocks verkabeln.

Wenn Sie wirklich darauf bestehen, können Sie das verwenden Runkit -Erweiterung Dies ändert das Programmiermodell von PHP, sodass Sie zur Laufzeit Kurse und Funktionen neu definieren können. Dies ist jedoch eine externe und nicht standardmäßige Erweiterungen, also denken Sie daran. Der Defacto -Standard ist ein manueller Ansatz, wie ich oben beschrieben habe.

Andere Tipps

Hier ist ein interessanter Artikel Das schreibt über Verspottung globaler PHP -Funktionen. Der Autor schlägt eine sehr kreative Lösung für "Mock" (Art Off) vor, die die globalen PHP -Funktionen überschreiben, indem die Methoden im Namespace des SUT (zu Test) überschreiben.

Hier Code aus einem Beispiel im Blog -Beitrag, in dem die time Funktion ist verspottet:

<?php

namespace My\Namespace;

use PHPUnit_Framework_TestCase;

/**
 * Override time() in current namespace for testing
 *
 * @return int
 */
function time()
{
    return SomeClassTest::$now ?: \time();
}

class SomeClassTest extends PHPUnit_Framework_TestCase
{
    /**
     * @var int $now Timestamp that will be returned by time()
     */
    public static $now;

    /**
     * @var SomeClass $someClass Test subject
     */
    private $someClass;

    /**
     * Create test subject before test
     */
    protected function setUp()
    {
        parent::setUp();
        $this->someClass = new SomeClass;
    }

    /**
     * Reset custom time after test
     */
    protected function tearDown()
    {
        self::$now = null;
    }

    /*
     * Test cases
     */
    public function testOneHourAgoFromNoon()
    {
        self::$now = strtotime('12:00');
        $this->assertEquals('11:00', $this->someClass->oneHourAgo());
    }
    public function testOneHourAgoFromMidnight()
    {
        self::$now = strtotime('0:00');
        $this->assertEquals('23:00', $this->someClass->oneHourAgo());
    }
}

Ich bin mir nicht sicher, ob dies ein guter Weg ist, es zu tun, aber es funktioniert sicher gut und ich denke, es ist hier erwähnenswert. Könnte ein Essen für eine Diskussion sein ...

Es gibt eine Phpunit -Erweiterung, die Runkit intern verwendet und in der Lage ist, Invocation -Matcher, Parameterbeschränkungen und alles zu verwenden, was ein verspottetes Objekt kann.

https://github.com/tcz/phpunit-mockfunction

In der Umgebung von PHP 5.3+ können Sie die Notwendigkeit zur Verwendung von Gebrauch machen runkit Erweiterung durch Hacken der Namespaces. Die einzige Voraussetzung darin, dass die Funktionsaufrufe nicht vollständig qualifiziert werden \mysql_query() - Und sie tun es normalerweise nicht. Anschließend können Sie dieselbe Funktion in Ihrem Test definieren, indem Sie den Test in einem Namespace definieren, und PHP ruft Ihre Funktion anstelle des globalen auf. Persönlich verwende ich diesen Ansatz, um die time() Funktionsaufruf. Hier ist ein schönes Beispiel mit dem Spott -Framework

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top