Zend_Test-PHPUnit-Examples.xml 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 15157 -->
  3. <!-- Reviewed: no -->
  4. <sect2 id="zend.test.phpunit.examples">
  5. <title>Beispiele</title>
  6. <para>
  7. Zu wissen wir man die eigene Infrastruktur für Tests einstellt und wir Ausnahmen zu erstellen sind ist
  8. nur der halbe Kampf; jetzt ist es Zeit auf einige Testszenarien zu schauen und zu eruieren wie diese
  9. verwendet werden können.
  10. </para>
  11. <example id="zend.test.phpunit.examples.userController">
  12. <title>Den UserController testen</title>
  13. <para>
  14. Nehmen wir einen standard Task für eine Webseite an: Authentifizierung und Registrierung von
  15. Benutzern. In unserem Beispiel definieren wir einen UserController um das zu behandeln, und haben
  16. die folgenden Notwendigkeiten:
  17. </para>
  18. <itemizedlist>
  19. <listitem><para>
  20. Wenn ein Benutzer nicht authentifiziert ist, wird er immer zur Login Seite des Kontrollers
  21. umgeleitet, unabhängig von der spezifizierten Aktion.
  22. </para></listitem>
  23. <listitem><para>
  24. Die Login Formularseite wird beides zeigen, das Login Formular und das Registrations Formular.
  25. </para></listitem>
  26. <listitem><para>
  27. Die angabe von ungültigen Anmeldedaten sollte in der Rückgabe des Login Formulars resultieren.
  28. </para></listitem>
  29. <listitem><para>
  30. Das Ansehen der Anmeldedaten sollte in einer Umleitung zur Profilseite des Benutzers resultieren.
  31. </para></listitem>
  32. <listitem><para>
  33. Die Profilseite sollte verändert werden um den Benutzernamen des Benutzers zu enthalten.
  34. </para></listitem>
  35. <listitem><para>
  36. Authentifizierte Benutzer welche die Loginseite besuchen sollten zu Ihrer Profilseite
  37. umgeleitet werden.
  38. </para></listitem>
  39. <listitem><para>
  40. Bei der Abmeldung, sollten ein Benutzer zur Loginseite umgeleitet werden.
  41. </para></listitem>
  42. <listitem><para>
  43. Mit ungültigen Daten sollte die Registrierung fehlschlagen.
  44. </para></listitem>
  45. </itemizedlist>
  46. <para>
  47. Wir können, und sollten zusätzliche Tests definieren, aber diese reichen für jetzt.
  48. </para>
  49. <para>
  50. Für unsere Anwendung definieren wir ein Plugin, 'Initialisieren' es, damit es bei
  51. <code>routeStartup()</code> läuft. Das erlaubt es uns das Bootstrapping in einem OOP Interface
  52. zu kapseln, was auch einen einfachen Weg bietet um ein Callback zu ermöglichen. Schauen wir uns
  53. erstmals die Basics dieser Klasse an:
  54. </para>
  55. <programlisting role="php"><![CDATA[
  56. class Bugapp_Plugin_Initialize extends Zend_Controller_Plugin_Abstract
  57. {
  58. /**
  59. * @var Zend_Config
  60. */
  61. protected static $_config;
  62. /**
  63. * @var string Aktuelle Umgebung
  64. */
  65. protected $_env;
  66. /**
  67. * @var Zend_Controller_Front
  68. */
  69. protected $_front;
  70. /**
  71. * @var string Pfad zum Root der Anwendung
  72. */
  73. protected $_root;
  74. /**
  75. * Constructor
  76. *
  77. * Umgebung, Root Pfad und Konfiguration initialisieren
  78. *
  79. * @param string $env
  80. * @param string|null $root
  81. * @return void
  82. */
  83. public function __construct($env, $root = null)
  84. {
  85. $this->_setEnv($env);
  86. if (null === $root) {
  87. $root = realpath(dirname(__FILE__) . '/../../../');
  88. }
  89. $this->_root = $root;
  90. $this->initPhpConfig();
  91. $this->_front = Zend_Controller_Front::getInstance();
  92. }
  93. /**
  94. * Route beginnen
  95. *
  96. * @return void
  97. */
  98. public function routeStartup(Zend_Controller_Request_Abstract $request)
  99. {
  100. $this->initDb();
  101. $this->initHelpers();
  102. $this->initView();
  103. $this->initPlugins();
  104. $this->initRoutes();
  105. $this->initControllers();
  106. }
  107. // Die Definition von Methoden würde hier folgen...
  108. }
  109. ]]></programlisting>
  110. <para>
  111. Das erlaubt es uns einen Bootstrap Callback wie folgt zu erstellen:
  112. </para>
  113. <programlisting role="php"><![CDATA[
  114. class UserControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
  115. {
  116. public function appBootstrap()
  117. {
  118. $controller = $this->getFrontController();
  119. $controller->registerPlugin(
  120. new Bugapp_Plugin_Initialize('development')
  121. );
  122. }
  123. public function setUp()
  124. {
  125. $this->bootstrap = array($this, 'appBootstrap');
  126. parent::setUp();
  127. }
  128. // ...
  129. }
  130. ]]></programlisting>
  131. <para>
  132. Sobald das fertig ist, können wir unsere Tests schreiben. Trotzdem, was ist mit den Tests die
  133. erfordern das der Benutzer angemeldet ist? Die einfache Lösung besteht darin das unsere
  134. Anwendungslogik das macht... und ein bischen trickst indem die <code>resetRequest()</code> und
  135. <code>resetResponse()</code> Methoden verwendet werden, die es uns erlauben eine andere Anfrage
  136. abzusetzen.
  137. </para>
  138. <programlisting role="php"><![CDATA[
  139. class UserControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
  140. {
  141. // ...
  142. public function loginUser($user, $password)
  143. {
  144. $this->request->setMethod('POST')
  145. ->setPost(array(
  146. 'username' => $user,
  147. 'password' => $password,
  148. ));
  149. $this->dispatch('/user/login');
  150. $this->assertRedirectTo('/user/view');
  151. $this->resetRequest()
  152. ->resetResponse();
  153. $this->request->setPost(array());
  154. // ...
  155. }
  156. // ...
  157. }
  158. ]]></programlisting>
  159. <para>
  160. Jetzt schreiben wir Tests:
  161. </para>
  162. <programlisting role="php"><![CDATA[
  163. class UserControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
  164. {
  165. // ...
  166. public function testCallWithoutActionShouldPullFromIndexAction()
  167. {
  168. $this->dispatch('/user');
  169. $this->assertController('user');
  170. $this->assertAction('index');
  171. }
  172. public function testLoginFormShouldContainLoginAndRegistrationForms()
  173. {
  174. $this->dispatch('/user');
  175. $this->assertQueryCount('form', 2);
  176. }
  177. public function testInvalidCredentialsShouldResultInRedisplayOfLoginForm()
  178. {
  179. $request = $this->getRequest();
  180. $request->setMethod('POST')
  181. ->setPost(array(
  182. 'username' => 'bogus',
  183. 'password' => 'reallyReallyBogus',
  184. ));
  185. $this->dispatch('/user/login');
  186. $this->assertNotRedirect();
  187. $this->assertQuery('form');
  188. }
  189. public function testValidLoginShouldRedirectToProfilePage()
  190. {
  191. $this->loginUser('foobar', 'foobar');
  192. }
  193. public function testAuthenticatedUserShouldHaveCustomizedProfilePage()
  194. {
  195. $this->loginUser('foobar', 'foobar');
  196. $this->request->setMethod('GET');
  197. $this->dispatch('/user/view');
  198. $this->assertNotRedirect();
  199. $this->assertQueryContentContains('h2', 'foobar');
  200. }
  201. public function
  202. testAuthenticatedUsersShouldBeRedirectedToProfileWhenVisitingLogin()
  203. {
  204. $this->loginUser('foobar', 'foobar');
  205. $this->request->setMethod('GET');
  206. $this->dispatch('/user');
  207. $this->assertRedirectTo('/user/view');
  208. }
  209. public function testUserShouldRedirectToLoginPageOnLogout()
  210. {
  211. $this->loginUser('foobar', 'foobar');
  212. $this->request->setMethod('GET');
  213. $this->dispatch('/user/logout');
  214. $this->assertRedirectTo('/user');
  215. }
  216. public function testRegistrationShouldFailWithInvalidData()
  217. {
  218. $data = array(
  219. 'username' => 'This will not work',
  220. 'email' => 'this is an invalid email',
  221. 'password' => 'Th1s!s!nv@l1d',
  222. 'passwordVerification' => 'wrong!',
  223. );
  224. $request = $this->getRequest();
  225. $request->setMethod('POST')
  226. ->setPost($data);
  227. $this->dispatch('/user/register');
  228. $this->assertNotRedirect();
  229. $this->assertQuery('form .errors');
  230. }
  231. }
  232. ]]></programlisting>
  233. <para>
  234. Es ist zu beachten das die Tests knapp sind und, für die meisten von Ihnen, nicht den aktuellen
  235. Inhalt berücksichtigen. Stattdessen sehen Sie nach Teilen in der Anfrage -- Anfrage Codes und Header
  236. sowie DOM Knoten. Das erlaubt es schnell zu prüfen das die Strukturen wie erwartet sind -- und
  237. verhinter das die Tests jedesmal wenn der Site neue Inhalte hinzugefügt werden darin ersticken.
  238. </para>
  239. <para>
  240. Es ist auch zu beachten das wir die Struktur des Dokuments in unseren Tests verwenden. Zum Beispiel
  241. schauen wir im letzten Test nach einer Form die einen Node mit der Klasse "errors" hat; das erlaubt
  242. es uns lediglich nach dem Vorhandensein von Form-Prüfungsfehlern zu testen, und uns keine Sorgen
  243. darüber zu machen warum spezielle Fehler überhaupt geworfen werden.
  244. </para>
  245. <para>
  246. Diese Anwendung <emphasis>könnte</emphasis> eine Datenbank verwenden. Wenn dem so ist, muß man
  247. warscheinlich einige Grundlagen ändern um sicherzustellen das die Datenbank am Anfang jeden Tests,
  248. in einer unverfälschten, testbaren Konfiguration ist. PHPUnit bietet bereits Funktionalität um
  249. das sicherzustellen; <ulink url="http://www.phpunit.de/pocket_guide/3.3/en/database.html">Lesen Sie
  250. darüber in der PHPUnit Dokumentation nach</ulink>. Wir empfehlen eine separate Datenbank für das
  251. Testen zu verwenden statt der Produktionsdatenbank, und entweder eine SQLite Datei oder eine
  252. Datenbank im Speicher zu verwenden, da beide Optionen sehr performant sind, keinen separaten
  253. Server benötigen, und die meisten SQL Syntaxe verwenden können.
  254. </para>
  255. </example>
  256. </sect2>
  257. <!--
  258. vim:se ts=4 sw=4 et:
  259. -->