Heim > Backend-Entwicklung > PHP-Tutorial > Erste Schritte mit TDD mit phpUnit

Erste Schritte mit TDD mit phpUnit

WBOY
Freigeben: 2016-08-08 09:29:49
Original
1445 Leute haben es durchsucht

Mit phpunit TDD-Serien üben

Beginnen Sie mit einem Bankkonto

Angenommen, Sie haben phpunit installiert.

Wir beginnen mit einem einfachen Beispiel eines Bankkontos, um die Idee von TDD (Test-Driven-Development) zu verstehen.

Erstellen Sie zwei Verzeichnisse, src und test, unter dem Projektverzeichnis, erstellen Sie die Datei src unter BankAccount.php und erstellen Sie die Datei test unter dem Verzeichnis BankAccountTest.php.

Gemäß der Idee von TDD schreiben wir zuerst Tests und dann Produktionscode, also bleibt BankAccount.php leer und wir schreiben zuerst BankAccountTest.php.

<code><?php
class BankAccountTest extends PHPUnit_Framework_TestCase
{
}
?></code>
Nach dem Login kopieren

Jetzt lassen Sie es uns ausführen und die Ergebnisse sehen. Die Befehlszeile zum Ausführen von phpunit lautet wie folgt:

<code>phpunit --bootstrap src/BankAccount.php test/BankAccountTest.php</code>
Nach dem Login kopieren

--bootstrap src/BankAccount.php bedeutet, dass src/BankAccount.php geladen wird, bevor der Testcode ausgeführt wird. Der auszuführende Testcode ist test/BankAccountTest.php.

Wenn Sie keine bestimmte Testdatei angeben und nur ein Verzeichnis angeben, führt phpunit alle Dateien im Verzeichnis aus, deren Dateinamen mit *Test.php übereinstimmen. Da es nur eine Datei test im Verzeichnis BankAccountTest.php gibt, führen Sie

aus
<code>phpunit --bootstrap src/BankAccount.php test</code>
Nach dem Login kopieren

wird das gleiche Ergebnis erzielen.

<code>There was 1 failure:

1) Warning
No tests found in class "BankAccountTest".

FAILURES!
Tests: 1, Assertions: 0, Failures: 1.</code>
Nach dem Login kopieren

Ein Warnfehler, da keine Tests vorhanden sind.

Kontoinstanziierung

Fügen wir unten einen Test hinzu. Beachten Sie, dass TDD eine Entwurfsmethode ist, die Ihnen dabei helfen kann, die Funktionalität eines Moduls von Grund auf zu entwerfen. Wenn wir Tests schreiben, müssen wir aus der Perspektive des Benutzers beginnen. Was macht der Benutzer zuerst, wenn er unsere Klasse BankAccount verwendet? Es muss eine neue Instanz von BankAccount sein. Unser erster Test ist also der Test der Instanziierung .

<code>public function testNewAccount(){
    $account1 = new BankAccount();
}</code>
Nach dem Login kopieren

Das Ausführen von phpunit ist wie erwartet fehlgeschlagen.

<code>PHP Fatal error:  Class 'BankAccount' not found in /home/wuchen/projects/jolly-code-snippets/php/phpunit/test/BankAccountTest.php on line 5</code>
Nach dem Login kopieren

Keine Definition der Klasse BankAccount gefunden. Als Nächstes schreiben wir den Produktionscode. Machen Sie den Test erfolgreich. Geben Sie in src/BankAccount.php (im Folgenden als Quelldatei bezeichnet) den folgenden Inhalt ein:

<code><?php
class BankAccount {
}
?></code>
Nach dem Login kopieren

Führen Sie phpunit aus und der Test ist erfolgreich.

<code>OK (1 test, 0 assertions)</code>
Nach dem Login kopieren

Als nächstes müssen wir Tests hinzufügen, damit die Tests fehlschlagen. Wenn Sie ein neues Konto erstellen, sollte der Kontostand 0 sein. Deshalb haben wir eine assert-Anweisung hinzugefügt:

<code>public function testNewAccount(){
    $account1 = new BankAccount();
    $this->assertEquals(0, $account1->value());
}</code>
Nach dem Login kopieren

Beachten Sie, dass value() eine Mitgliedsfunktion von BankAccount ist. Natürlich wurde diese Funktion noch nicht definiert. Als Benutzer hoffen wir, dass BankAccount diese Funktion bereitstellt.

Führen Sie phpunit aus, die Ergebnisse sind wie folgt:

<code>PHP Fatal error:  Call to undefined method BankAccount::value() in /home/wuchen/projects/jolly-code-snippets/php/phpunit/test/BankAccountTest.php on line 6</code>
Nach dem Login kopieren

Das Ergebnis zeigt uns, dass BankAccount nicht über die Memberfunktion value() verfügt. Produktionscode hinzufügen:

<code>class BankAccount {
    public function value(){
        return 0;
    }
}</code>
Nach dem Login kopieren

Warum sollte value() direkt 0 zurückgeben, weil der Testcode erwartet, dass value() 0 zurückgibt? Das Prinzip von TDD besteht darin, keinen redundanten Produktionscode zu schreiben, sondern nur so viel, dass der Test bestanden werden kann.

Kontozugriff

Nachdem

phpunit ausgeführt und bestanden hat, gehen wir zunächst davon aus, dass die Instanziierung von BankAccount die Anforderungen erfüllt hat. Wie möchte der Benutzer dann BankAccount verwenden? Sie möchten auf jeden Fall Geld einzahlen. Ich hoffe, dass BankAccount über eine Einzahlungsfunktion verfügt. Also fügen wir den nächsten Test hinzu.

<code>public function testDeposit(){
    $account = new BankAccount();
    $account->deposit(10);
    $this->assertEquals(10, $account->value());
}</code>
Nach dem Login kopieren

Der Anfangssaldo des Kontos beträgt 0. Wenn wir 10 Yuan darauf einzahlen, sollte der Kontostand natürlich 10 betragen. Beim Ausführen von phpunit schlägt der Test fehl, da die Einzahlungsfunktion nicht definiert wurde:

<code>.PHP Fatal error:  Call to undefined method BankAccount::deposit() in /home/wuchen/projects/jolly-code-snippets/php/phpunit/test/BankAccountTest.php on line 11</code>
Nach dem Login kopieren

Als nächstes fügen Sie die Einzahlungsfunktion in der Quelldatei hinzu:

<code>public function deposit($ammount) {
}</code>
Nach dem Login kopieren

Führen Sie phpunit erneut aus und erhalten Sie die folgenden Ergebnisse:

<code>1) BankAccountTest::testDeposit
Failed asserting that 0 matches expected 10.</code>
Nach dem Login kopieren

Da wir den Kontostand zu diesem Zeitpunkt nicht in der Einzahlungsfunktion bearbeitet haben, beträgt der Anfangswert des Kontostands 0 und ist nach Ausführung der Einzahlungsfunktion immer noch 0, was nicht dem vom Benutzer erwarteten Verhalten entspricht . Wir sollten den vom Benutzer eingezahlten Betrag zum Guthaben hinzufügen.

Um den Kontostand zu verwalten, sollte der Kontostand eine Mitgliedsvariable von BankAccount sein. Diese Variable darf von der Außenwelt nicht geändert werden und ist daher als private Variable definiert. Als nächstes fügen wir die private Variable $value zum Produktionscode hinzu, dann sollte die Funktion value den Wert von $value zurückgeben.

<code>class BankAccount {
    private $value;
    
    public function value(){
        return $this->value;
    }

    public function deposit($ammount) {
        $this->value = 10;
    }
}</code>
Nach dem Login kopieren

Führen Sie phpunit aus und der Test ist erfolgreich. Als nächstes dachten wir: Was brauchen Benutzer sonst noch? Ja, Geld abheben. Beim Abheben von Geld wird dieser Wert vom Kontostand abgezogen. Wenn Sie der Funktion deposit eine negative Zahl übergeben, entspricht dies einer Geldabhebung.
Also fügen wir der testDeposit-Funktion des Testcodes zwei Codezeilen hinzu.

<code>$account->deposit(-5);
$this->assertEquals(5, $account->value());</code>
Nach dem Login kopieren

Führen Sie phpunit erneut aus und der Test ist fehlgeschlagen.

<code>1) BankAccountTest::testDeposit
Failed asserting that 10 matches expected 5.</code>
Nach dem Login kopieren

Das liegt daran, dass wir im Produktionscode einfach $value auf das Ergebnis 10 gesetzt haben. Verbessern Sie den Produktionscode.

<code>public function deposit($ammount) {
    $this->value += $ammount;
}</code>
Nach dem Login kopieren

Führen Sie phpunit erneut aus und der Test ist erfolgreich.

Neuer Konstruktor

Als nächstes kam mir der Gedanke, dass der Benutzer möglicherweise einen anderen Konstruktor benötigt, der beim Erstellen des BankAccount-Objekts einen Wert als Kontostand übergeben könnte. Deshalb haben wir diesen Instanziierungstest in testNewAccount hinzugefügt.

<code>public function testNewAccount(){
    $account1 = new BankAccount();
    $this->assertEquals(0, $account1->value());
    $account2 = new BankAccount(10);
    $this->assertEquals(10, $account2->value());
}</code>
Nach dem Login kopieren

Führen Sie phpunit aus, das Ergebnis ist:

<code>1) BankAccountTest::testNewAccount
Failed asserting that null matches expected 10.</code>
Nach dem Login kopieren

这时因为BankAccount没有带参数的构造函数,因此new BankAccount(10)会返回一个空对象,空对象的value()函数自然返回的也是null。为了通过测试,我们在生产代码中增加带参数的构造函数。

<code>public function __construct($n){
    $this->value = $n;
}</code>
Nach dem Login kopieren

再运行测试:

<code>1) BankAccountTest::testNewAccount
Missing argument 1 for BankAccount::__construct(), called in /home/wuchen/projects/jolly-code-snippets/php/phpunit/test/BankAccountTest.php on line 5 and defined

/home/wuchen/projects/jolly-code-snippets/php/phpunit/src/BankAccount.php:5
/home/wuchen/projects/jolly-code-snippets/php/phpunit/test/BankAccountTest.php:5

2) BankAccountTest::testDeposit
Missing argument 1 for BankAccount::__construct(), called in /home/wuchen/projects/jolly-code-snippets/php/phpunit/test/BankAccountTest.php on line 12 and defined

/home/wuchen/projects/jolly-code-snippets/php/phpunit/src/BankAccount.php:5
/home/wuchen/projects/jolly-code-snippets/php/phpunit/test/BankAccountTest.php:12</code>
Nach dem Login kopieren

两个调用new BankAccount()的地方都报告了错误,增加了带参数的构造函数,不带参数的构造函数又不行了。从c++/java过渡来的同学马上想到增加一个默认的构造函数:

<code>public function __construct() {
    $this->value = 0;
}</code>
Nach dem Login kopieren

但这样是不行的,因为php不支持函数重载,所以不能有多个构造函数。

怎么办?对了,我们可以为参数增加默认值。修改构造函数为:

<code>public function __construct($n = 0){
    $this->value = $n;
}</code>
Nach dem Login kopieren

这样调用 new BankAccount()时,相当于传递了0给构造函数,满足了需求。
phpunit运行以下,测试通过。

这时,我们的生产代码为:

<code><?php
class BankAccount {
    private $value;             // default to 0

    public function __construct($n = 0){
        $this->value = $n;
    }
    
    public function value(){
        return $this->value;
    }

    public function deposit($ammount) {
        $this->value += $ammount;
    }
}
?></code>
Nach dem Login kopieren

总结

虽然我们的代码并不多,但是每一步都写得很有信心,这就是TDD的好处。即使你对php的语法不是很有把握(比如我),也可以对自己的代码很有信心。

用TDD的方式写程序的另一个好处,就是编码之前不需要对单个模块进行仔细的设计,可以在写测试的时候进行设计。这样开发出来的模块既可以满足用户需要,也不会冗余。

后面将会介绍 phpunit 的更多用法。

以上就介绍了用phpUnit入门TDD,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage