Zend_Test-PHPUnit-Db-Testing.xml 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 17054 -->
  3. <!-- Reviewed: no -->
  4. <sect2 id="zend.test.phpunit.db.testing">
  5. <title>Usage, API and Extensions Points</title>
  6. <para>
  7. The Quickstart already gave a good introduction on how database testing can be done using
  8. PHPUnit and the Zend Framework. This section gives an overview over the API that the
  9. <classname>Zend_Test_PHPUnit_Db</classname> component comes with and how it works
  10. internally.
  11. </para>
  12. <note>
  13. <title>Some Remarks on Database Testing</title>
  14. <para>
  15. Just as the Controller TestCase is testing an application at an integration level, the
  16. Database TestCase is an integration testing method. Its using several different
  17. application layers for testing purposes and therefore should be consumed with caution.
  18. </para>
  19. <para>
  20. It should be noted that testing domain and business logic with integration tests such
  21. as Zend Framework's Controller and Database TestCases is a bad practice. The purpose of
  22. an Integration test is to check that several parts of an application work smoothly when
  23. wired together. These integration tests do not replace the need for a set of unit tests
  24. that test the domain and business logic at a much smaller level, the isolated class.
  25. </para>
  26. </note>
  27. <sect3 id="zend.test.phpunit.db.testing.testcase">
  28. <title>The Zend_Test_PHPUnit_DatabaseTestCase class</title>
  29. <para>
  30. The <classname>Zend_Test_PHPUnit_DatabaseTestCase</classname> class derives from the
  31. <classname>PHPUnit_Extensions_Database_TestCase</classname> which allows to setup tests
  32. with a fresh database fixture on each run easily. The Zend implementation offers some
  33. additional convenience features over the PHPUnit Database extension when it comes to
  34. using <classname>Zend_Db</classname> resources inside your tests. The workflow of a
  35. database test-case can be described as follows.
  36. </para>
  37. <orderedlist>
  38. <listitem>
  39. <para>
  40. For each test PHPUnit creates a new instance of the TestCase and calls the
  41. <methodname>setUp()</methodname> method.
  42. </para>
  43. </listitem>
  44. <listitem>
  45. <para>
  46. The Database TestCase creates an instance of a Database Tester which handles the
  47. setting up and tearing down of the database.
  48. </para>
  49. </listitem>
  50. <listitem>
  51. <para>
  52. The database tester collects the information on the database connection and
  53. initial dataset from <methodname>getConnection()</methodname> and
  54. <methodname>getDataSet()</methodname> which are both abstract methods and have
  55. to be implemented by any Database Testcase.
  56. </para>
  57. </listitem>
  58. <listitem>
  59. <para>
  60. By default the database tester truncates the tables specified in the given
  61. dataset, and then inserts the data given as initial fixture.
  62. </para>
  63. </listitem>
  64. <listitem>
  65. <para>
  66. When the database tester has finished setting up the database, PHPUnit runs the
  67. test.
  68. </para>
  69. </listitem>
  70. <listitem>
  71. <para>
  72. After running the test, <methodname>tearDown()</methodname> is called. Because
  73. the database is wiped in <methodname>setUp()</methodname> before inserting the
  74. required initial fixture, no actions are executed by the database tester at this
  75. stage.
  76. </para>
  77. </listitem>
  78. </orderedlist>
  79. <note>
  80. <para>
  81. The Database TestCase expects the database schema and tables to be setup correctly
  82. to run the tests. There is no mechanism to create and tear down database tables.
  83. </para>
  84. </note>
  85. <para>
  86. The <classname>Zend_Test_PHPUnit_DatabaseTestCase</classname> class has some convenience
  87. functions that can help writing tests that interact with the database and the database
  88. testing extension.
  89. </para>
  90. <para>
  91. The next table lists only the new methods compared to the
  92. <classname>PHPUnit_Extensions_Database_TestCase</classname>, whose <ulink
  93. url="http://www.phpunit.de/manual/current/en/database.html">API is documented in
  94. the PHPUnit Documentation</ulink>.
  95. </para>
  96. <table id="zend.test.phpunit.db.testing.testcase.api-methods">
  97. <title>Zend_Test_PHPUnit_DatabaseTestCase API Methods</title>
  98. <tgroup cols="2">
  99. <thead>
  100. <row>
  101. <entry>Method</entry>
  102. <entry>Description</entry>
  103. </row>
  104. </thead>
  105. <tbody>
  106. <row>
  107. <entry>
  108. <methodname>createZendDbConnection(Zend_Db_Adapter_Abstract $connection,
  109. $schema)</methodname>
  110. </entry>
  111. <entry>
  112. Create a PHPUnit Database Extension compatible Connection instance from
  113. a <classname>Zend_Db_Adapter_Abstract</classname> instance. This method
  114. should be used in for testcase setup when implementing the abstract
  115. <methodname>getConnection()</methodname> method of the database testcase.
  116. </entry>
  117. </row>
  118. <row>
  119. <entry><methodname>getAdapter()</methodname></entry>
  120. <entry>
  121. Convenience method to access the underlying
  122. <classname>Zend_Db_Adapter_Abstract</classname> instance which is nested
  123. inside the PHPUnit database connection created with
  124. <methodname>getConnection()</methodname>.
  125. </entry>
  126. </row>
  127. <row>
  128. <entry>
  129. <methodname>createDbRowset(Zend_Db_Table_Rowset_Abstract $rowset,
  130. $tableName = null)</methodname>
  131. </entry>
  132. <entry>
  133. Create a DataTable Object that is filled with the data from a given
  134. <classname>Zend_Db_Table_Rowset_Abstract</classname> instance. The table
  135. the rowset is connected to is chosen when <code>$tableName</code> is
  136. null.
  137. </entry>
  138. </row>
  139. <row>
  140. <entry>
  141. <methodname>createDbTable(Zend_Db_Table_Abstract $table, $where = null,
  142. $order = null, $count = null, $offset = null)</methodname>
  143. </entry>
  144. <entry>
  145. Create a DataTable object that represents the data contained in a
  146. <classname>Zend_Db_Table_Abstract</classname> instance. For retrieving
  147. the data <methodname>fetchAll()</methodname> is used, where the optional
  148. parameters can be used to restrict the data table to a certain subset.
  149. </entry>
  150. </row>
  151. <row>
  152. <entry>
  153. <methodname>createDbTableDataSet(array $tables=array())</methodname>
  154. </entry>
  155. <entry>
  156. Create a DataSet containing the given <code>$tables</code>, an array of
  157. <classname>Zend_Db_Table_Abstract</classname> instances.
  158. </entry>
  159. </row>
  160. </tbody>
  161. </tgroup>
  162. </table>
  163. </sect3>
  164. <sect3 id="zend.test.phpunit.db.testing.controllerintegration">
  165. <title>Integrating Database Testing with the ControllerTestCase</title>
  166. <para>
  167. Because PHP does not support multiple inheritance it is not possible to use the
  168. Controller and Database testcases in conjunction. However you can use the
  169. <classname>Zend_Test_PHPUnit_Db_SimpleTester</classname> database tester in your
  170. controller test-case to setup a database enviroment fixture for each new controller
  171. test. The Database TestCase in general is only a set of convenience functions which can
  172. also be accessed and used without the test case.
  173. </para>
  174. <example id="zend.test.phpunit.db.testing.controllerintegration.example">
  175. <title>Database integration example</title>
  176. <para>
  177. This example extends the User Controller Test from the
  178. <classname>Zend_Test_PHPUnit_ControllerTestCase</classname> documentation to include
  179. a database setup.
  180. </para>
  181. <programlisting language="php"><![CDATA[
  182. class UserControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
  183. {
  184. public function setUp()
  185. {
  186. $this->setupDatabase();
  187. $this->bootstrap = array($this, 'appBootstrap');
  188. parent::setUp();
  189. }
  190. public function setupDatabase()
  191. {
  192. $db = Zend_Db::factory(...);
  193. $connection = Zend_Test_PHPUnit_Db_Connection($db,
  194. 'database_schema_name');
  195. $databaseTester = new Zend_Test_PHPUnit_Db_SimpleTester($connection);
  196. $databaseFixture =
  197. new PHPUnit_Extensions_Database_DataSet_FlatXmlDataSet(
  198. dirname(__FILE__) . '/_files/initialUserFixture.xml'
  199. );
  200. $databaseTester->setupDatabase($databaseFixture);
  201. }
  202. }
  203. ]]></programlisting>
  204. <para>
  205. Now the Flat XML dataset "initialUserFixture.xml" is used to set the database into
  206. an initial state before each test, exactly as the DatabaseTestCase works internally.
  207. </para>
  208. </example>
  209. </sect3>
  210. </sect2>