Zend_Test-PHPUnit-Examples.xml 10 KB

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