Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Geleitwort
Vorwort
1 PEAR – Einführung
2 Authentication
3 Caching
4 Date and Time
5 File Formats
6 HTTP
7 Internationalization
8 Mail
9 Networking
10 PHP
11 Text
12 Web Services
13 Benchmarking
14 Configuration
15 Database
16 File System
17 HTML
18 Images
19 Logging
20 Math
21 Numbers
22 Tools and Utilities
23 XML
24 Selbst Pakete erstellen
25 PECL
Index
Ihre Meinung?

Spacer
 <<   zurück
PHP PEAR von Carsten Möhrke
Anwendung und Entwicklung – Erweiterungen für PHP schreiben
Buch: PHP PEAR

PHP PEAR
798 S., 39,90 Euro
Rheinwerk Computing
ISBN 3-89842-580-0
gp 22 Tools and Utilities
  gp 22.1 PHPUnit2
  gp 22.2 PHPDocumentor

22 Tools and Utilities

In der Kategorie »Tools and Utilities« sind einige sehr hilfreiche Pakete enthalten, die Sie bei der Entwicklung unterstützen. Die beiden wichtigsten Pakete in dieser Kategorie sind sicher »PHPUnit2« zum automatisierten Testen von Software und »PHPDocumentor«, das Dokumentationen generieren kann.


Rheinwerk Computing

22.1 PHPUnit2  toptop


Besprochene Version: 2.2.0 Lizenz: PHP-Lizenz 3.0
Klassendatei(en): PHPUnit2/Framework/TestCase.php

PHPUnit ist ein Paket zum automatisierten Testen von Methoden und Klassen. PHPUnit2 ist der Nachfolger von PHPUnit, das schon lange im Einsatz ist.

PHPUnit2 soll also nicht unbedingt zum Bestandteil Ihrer Klassen werden, sondern es soll Sie nur dabei unterstützen, Ihre Klassen zu testen und eventuell vorhandene Fehler zu finden.

Die ideale Vorgehensweise wäre, dass Sie erst definieren, was Ihre Klasse leisten soll. Das heißt, beim Entwurf der Software definieren Sie, wie eine Methode heißt und was ihre Aufgabe ist bzw. welchen Wert sie zurückgibt. Diese Vorgehensweise hat den großen Vorteil, dass Sie beim Testen nicht auf die Idee kommen, die Tests an Ihre Programmierung anzupassen, um damit »nicht ganz so richtiges« Verhalten zu kaschieren.

Die Schnittstellen und das Verhalten der Methoden vor der Implementation zu definieren hat auch den Vorteil, dass die Entwicklung besser auf verschiedene Programmierer aufgeteilt werden kann.

In diesem Beispiel soll eine Klasse shoppingCart für einen Einkaufswagen in einem Shop implementiert und getestet werden. Die Methoden der Klasse sollen Folgendes leisten:

  • integer getNumItems() Liefert die Anzahl der Artikel im Einkaufswagen als Integer-Wert zurück.
  • mixed addItem($item, $price, $quantity) Fügt dem Einkaufswagen einen Artikel hinzu und bekommt Artikelnummer, Preis und Anzahl übergeben. Der Rückgabewert ist die neue Anzahl der Artikel als Integer-Wert.
  • mixed reduceQuantity($item, $quantity) Reduziert die Menge eines Artikels im Warenkorb und bekommt die Artikelnummer und die Anzahl der zu entfernenden Artikel übergeben. Gibt im Erfolgsfall die neue Anzahl der Artikel als Integer-Wert zurück und sonst false.
  • getPriceTax() Liefert den Preis aller Artikel inklusive der Mehrwertsteuer von 16  % zurück.

Für einen produktiven Nutzen fehlen natürlich noch Methoden, aber für das Beispiel soll das reichen.

Haben Sie dieses Verhalten definiert, können Sie beginnen, die Testfälle zu implementieren. Hierbei handelt es sich um Methoden, die prüfen, ob die neu erstellten Methoden sich korrekt verhalten. Um die Testfälle zu implementieren, erweitern Sie die Klasse PHPUnit2_Framework_TestCase. In dieser neuen Klasse werden Methoden implementiert, die die eigentlichen Tests durchführen. Die Namen der Methoden müssen jeweils mit test beginnen und können auf vordefinierte Methoden zugreifen, die prüfen, ob die zu testenden Methoden sich korrekt verhalten.

Diese Methoden, die von der Klasse PHPUnit2_Framework_TestCase vererbt werden, finden Sie in Tabelle 22.1. Diese Methoden werden auch als Zusicherungsmethoden bezeichnet. Dieser Name resultiert daraus, dass die Methode, die getestet werden soll, ein bestimmtes Verhalten zusichert. Die Namen der Zusicherungsmethoden, die dieses Verhalten bestätigen, beginnen jeweils mit assert.


Tabelle 22.1 Definierte assert-Methoden
Testmethode Beschreibung
assertContains($n,$h) assertNotContains($n,$h) assertContains() prüft, ob der String $n im (Rückgabe-) Wert $h enthalten ist, und assertNotContains() prüft, ob das nicht der Fall ist.
assertEquals($e,$a,$m,$d) Testet, ob der aktuelle Wert $a dem erwarteten Wert $e entspricht. $m ist optional und definiert eine Meldung, die ausgegeben wird. $d ist auch optional und legt fest, wie weit $a von $e abweichen darf.
assertNull($v,$m) assertNotNull($v,$m) Diese Methoden prüfen, ob $v null bzw. nicht null ist, und geben, wenn die Bedingung nicht erfüllt ist, die optionale Nachricht $m aus.
assertSame($e,$a,$m) assertNotSame($e,$a,$m) Testet ob $e und $a dasselbe Objekt bzw. dieselbe Variable referenzieren bzw. nicht referenzieren. Schlägt der Test fehl wird der optionale Parameter $m ausgegeben.
assertTrue($c,$m) assertFalse($c,$m) Prüft ob die Bedingung $c, also z. B. '$a > 0', true bzw. false ist, und gibt den optionalen Wert $m aus, wenn das nicht der Fall ist.
assertRegExp($r,$s,$m) assertNotRegExp($r,$s,$m) Testet, ob der String $s mit dem regulären Ausdruck $r beschrieben wird bzw. ob das nicht der Fall ist. Gibt im Fehlerfall den optionalen Text $m aus.
assertType($e,$a,$m) assertNotType($e,$a,$m) Prüft, ob der Typ der aktuellen Variable $a dem erwarteten Typ $e entspricht bzw. ob das nicht der Fall ist, und gibt bei einem Fehlschlag die optionale Variable $m aus.

Eine Klasse für einen entsprechenden Test könnte wie in Listing 22.1 aussehen. Ich habe nicht alle Möglichkeiten in diesem Beispiel implementiert, da es sonst sehr umfangreich geworden wäre.

// Einbinden der PEAR-Klasse 
require_once('PHPUnit2/Framework/TestCase.php'); 
// Einbinden der zu testenden Klasse 
require_once('shoppingCart.php'); 
 
class tester extends PHPUnit2_Framework_TestCase 
{ 
   public function testInit() 
   { 
      $cart = new shoppingCart(); 
      // Neues Objekt darf noch keinen Inhalt haben 
      $this->assertEquals(0,$cart->getNumItems()); 
      // Keine Artikel, also muss der Preis Null sein 
      $this->assertEquals(0,$cart->getPriceTax()); 
   } 
 
   public function testAddItem() 
   { 
      $anzahl = 3; 
      $cart = new shoppingCart(); 
      // Artikel hinzufuegen 
      $res = $cart->addItem('1a233d',3.20,$anzahl); 
      // Stimmen Typ und Inhalt der Rueckgabe? 
      $this->assertType ('integer',$res); 
      $this->assertEquals($anzahl,$res); 
 
      //Korrekte Anzahl von Artikeln im Warenkorb? 
      $this->assertEquals($anzahl,$cart->getNumItems()); 
   } 
 
   public function testPrice() 
   { 
      $anzahl = 3; 
      $preis = 2.5; 
      $cart = new shoppingCart(); 
      $cart->addItem('abg',$preis,$anzahl); 
      // Preis auslesen 
      $res = $cart->getPriceTax(); 
      $erwartet = sprintf("%.2f",$anzahl*$preis*1.16); 
      // Weichen erwartetes und aktuelles Ergebnis voneinander ab? 
      // Rundungsfehler von 0.01 wird akzeptiert 
      $this->assertEquals($erwartet,$res,null,0.01); 
   } 
 
   public function testReduceQuantity() 
   { 
      $anzahl = 5; 
      $itemnr= 'gftfr'; 
      $cart = new shoppingCart(); 
      // 5 Artikel hinzufuegen 
      $cart->addItem($itemnr,3.20,$anzahl); 
      // Alle bis auf einen entfernen 
      $res = $cart->reduceQuantity($itemnr,($anzahl-1)); 
 
      $this->assertEquals(1,$cart->getNumItems()); 
 
      // Versuchen, noch zwei mehr zu entfernen 
      $cart->reduceQuantity($itemnr,2); 
 
      // Es muessen jetzt 0 Artikel im Wagen liegen 
      $this->assertEquals(0,$cart->getNumItems()); 
   } 
}

Listing 22.1 Test-Cases für die Vorgaben (tester.php)

Nachdem die Test-Cases definiert worden sind, fehlt natürlich noch die Klasse, die getestet werden soll. Diese finden Sie in Listing 22.2. Sie ist natürlich nur ein Beispiel und nicht ideal implementiert. Des Weiteren rechnet sie mit einem falschen Mehrwertsteuersatz.

class shoppingCart 
{ 
   // Array zum Verwalten der Daten 
   private $items=array(); 
 
   // Gibt die Anzahl der Artikel im Korb zurueck 
   public function getNumItems() 
   { 
      if (0 === count ($this->items)) 
      { 
         return 0; 
      } 
      else 
      { 
         $sum = 0; 
         foreach ($this->items as $item) 
         { 
            $sum +=$item['quantity'];  
         } 
         return $sum; 
      } 
   } 
 
 
   // Artikel hinzufuegen 
   public function addItem($item, $price, $quantity) 
   { 
      if (true ==isset($this->items[$item])) 
      { 
         $this->items[$item]['quantity']+=$quantity; 
      } 
      else 
      { 
         $this->items[$item]['quantity']=$quantity; 
         $this->items[$item]['price']=$price; 
      } 
      return $this->getNumItems(); 
   } 
 
   // Anzahl reduzieren 
   public function reduceQuantity($item, $quantity) 
   { 
      if (true ==isset($this->items[$item])) 
      { 
         if ($this->items[$item]['quantity'] > $quantity) 
         { 
            $this->items[$item]['quantity']-=$quantity; 
         } 
         else 
         { 
            unset ($this->items[$item]); 
         } 
         return ($this->getNumItems()); 
      } 
      return false; 
   } 
 
   // Preis inkl. Steuer auslesen 
   public function getPriceTax() 
   { 
      if (0 === count ($this->items)) 
      { 
         return 0; 
      } 
      else 
      { 
         $sum = 0; 
         foreach ($this->items as $item) 
         { 
            $sum +=$item['quantity']*$item['price'];  
         } 
         return (sprintf("%.2f",$sum*1.15)); 
      } 
   } 
}

Listing 22.2 Zu testende Klasse (shoppingCart.php)

Um den eigentlichen Test nach der Implementierung durchführen zu können, speichern Sie die Test-Klasse in einer PHP-Datei ab, deren Name der Klasse entspricht. In diesem Fall muss der Dateiname also tester.php lauten.

Der Aufruf des Tests erfolgt auf der Kommandozeile mit dem Befehl phpunit und dem Namen der Datei, die die Test-Klasse enthält.

www> phpunit tester.php 
PHPUnit 2.2.0 by Sebastian Bergmann. 
 
..F. 
 
Time: 0.003942 
There was 1 failure: 
1) testPrice(tester) 
expected same: <8.7> was not: <8.63> 
 
FAILURES!!! 
Tests run: 4, Failures: 1, Errors: 0, Incomplete Tests: 0.

Wie Sie sehen können, findet PHPUnit2 den falschen Rückgabewert bei der Berechnung des Gesamtpreises.

Das Paket bietet noch einige zusätzliche Features. Haben Sie schon eine fertige Klassendatei, können Sie das Programm phpunit mit dem Parameter --skeleton und dem Namen der Klassendatei aufrufen. In dem Fall würde eine Vorlage für eine Testdatei erstellt, auf die Sie dann aufbauen können.

Ein anderes Feature, das ganz hilfreich sein kann, ist TestDox. Wenn Sie das Programm mit dem Parameter --testdox-text oder mit dem Parameter --testdox-html aufrufen, wird automatisch eine (kleine) Dokumentation erstellt. Hinter dem Parameter müssen Sie den Namen der Datei angeben, unter dem die Dokumentation erstellt werden soll. Mit dem ersten Parameter erzeugt phpunit eine Text- und mit dem zweiten eine HTML-Datei.

 <<   zurück
     
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: PHP PEAR
PHP PEAR
Jetzt Buch bestellen!
 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: PHP 5.6 und MySQL 5.7






 PHP 5.6 und
 MySQL 5.7


Zum Rheinwerk-Shop: Einstieg in PHP 5.6 und MySQL 5.6






 Einstieg in PHP 5.6
 und MySQL 5.6


Zum Rheinwerk-Shop: Responsive Webdesign






 Responsive Webdesign


Zum Rheinwerk-Shop: Moderne Websites entwickeln






 Moderne Websites
 entwickeln


Zum Rheinwerk-Shop: MySQL 5.6






 MySQL 5.6


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo








Copyright © Rheinwerk Verlag GmbH 2007
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern