Zend_Test-PHPUnit-Db-Quickstart.xml 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- Reviewed: no -->
  3. <sect2 id="zend.test.phpunit.db.quickstart">
  4. <title>Quickstart</title>
  5. <sect3 id="zend.test.phpunit.db.quickstart.testcase">
  6. <title>Setup a Database TestCase</title>
  7. <para>
  8. We are now writting some database tests for the Bug Database example in the
  9. <classname>Zend_Db_Table</classname> documentation. First we begin to test that
  10. inserting a new bug is actually saved in the database correctly. First we have to
  11. setup a test-class that extends
  12. <classname>Zend_Test_PHPUnit_DatabaseTestCase</classname>. This class extends the
  13. PHPUnit Database Extension, which in turn extends the basic
  14. <classname>PHPUnit_Framework_TestCase</classname>. A database testcase contains two
  15. abstract methods that have to be implemented, one for the database connection and
  16. one for the initial dataset that should be used as seed or fixture.
  17. </para>
  18. <note>
  19. <para>
  20. You should be familiar with the PHPUnit Database extension to follow this quickstart
  21. easily. Although all the concepts are explained in this documentation it may be
  22. helpful to read the PHPUnit documentation first.
  23. </para>
  24. </note>
  25. <programlisting language="php"><![CDATA[
  26. class BugsTest extends Zend_Test_PHPUnit_DatabaseTestCase
  27. {
  28. private $_connectionMock;
  29. /**
  30. * Returns the test database connection.
  31. *
  32. * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection
  33. */
  34. protected function getConnection()
  35. {
  36. if($this->_connectionMock == null) {
  37. $connection = Zend_Db::factory(...);
  38. $this->_connectionMock = $this->createZendDbConnection(
  39. $connection, 'zfunittests'
  40. );
  41. Zend_Db_Table_Abstract::setDefaultAdapter($connection);
  42. }
  43. return $this->_connectionMock;
  44. }
  45. /**
  46. * @return PHPUnit_Extensions_Database_DataSet_IDataSet
  47. */
  48. protected function getDataSet()
  49. {
  50. return $this->createFlatXmlDataSet(
  51. dirname(__FILE__) . '/_files/bugsSeed.xml'
  52. );
  53. }
  54. }
  55. ]]></programlisting>
  56. <para>
  57. Here we create the database connection and seed some data into the database. Some
  58. important details should be noted on this code:
  59. </para>
  60. <itemizedlist>
  61. <listitem>
  62. <para>
  63. You cannot directly return a <classname>Zend_Db_Adapter_Abstract</classname>
  64. from the <methodname>getConnection()</methodname> method, but a PHPUnit
  65. specific wrapper which is generated with the
  66. <methodname>createZendDbConnection()</methodname> method.
  67. </para>
  68. </listitem>
  69. <listitem>
  70. <para>
  71. The database schema (tables and database) is not re-created on every
  72. testrun. The database and tables have to be created manually before running
  73. the tests.
  74. </para>
  75. </listitem>
  76. <listitem>
  77. <para>
  78. Database tests by default truncate the data during
  79. <methodname>setUp()</methodname> and then insert the seed data which is
  80. returned from the <methodname>getDataSet()</methodname> method.
  81. </para>
  82. </listitem>
  83. <listitem>
  84. <para>
  85. DataSets have to implement the interface
  86. <classname>PHPUnit_Extensions_Database_DataSet_IDataSet</classname>.
  87. There is a wide range of <acronym>XML</acronym> and YAML configuration file
  88. types included in PHPUnit which allows to specifiy how the tables and datasets
  89. should look like and you should look into the PHPUnit documentation to get the
  90. latest information on these dataset specifications.
  91. </para>
  92. </listitem>
  93. </itemizedlist>
  94. </sect3>
  95. <sect3 id="zend.test.phpunit.db.quickstart.dataset">
  96. <title>Specify a seed dataset</title>
  97. <para>
  98. In the previous setup for the database testcase we have specified a seed file for the
  99. database fixture. We now create this file specified in the Flat <acronym>XML</acronym>
  100. format:
  101. </para>
  102. <programlisting language="xml"><![CDATA[
  103. <?xml version="1.0" encoding="UTF-8" ?>
  104. <dataset>
  105. <zfbugs bug_id="1" bug_description="system needs electricity to run"
  106. bug_status="NEW" created_on="2007-04-01 00:00:00"
  107. updated_on="2007-04-01 00:00:00" reported_by="goofy"
  108. assigned_to="mmouse" verified_by="dduck" />
  109. <zfbugs bug_id="2" bug_description="Implement Do What I Mean function"
  110. bug_status="VERIFIED" created_on="2007-04-02 00:00:00"
  111. updated_on="2007-04-02 00:00:00" reported_by="goofy"
  112. assigned_to="mmouse" verified_by="dduck" />
  113. <zfbugs bug_id="3" bug_description="Where are my keys?" bug_status="FIXED"
  114. created_on="2007-04-03 00:00:00" updated_on="2007-04-03 00:00:00"
  115. reported_by="dduck" assigned_to="mmouse" verified_by="dduck" />
  116. <zfbugs bug_id="4" bug_description="Bug no product" bug_status="INCOMPLETE"
  117. created_on="2007-04-04 00:00:00" updated_on="2007-04-04 00:00:00"
  118. reported_by="mmouse" assigned_to="goofy" verified_by="dduck" />
  119. </dataset>
  120. ]]></programlisting>
  121. <para>
  122. We will work with this four entries in the database table "zfbugs" in the next
  123. examples. The required MySQL schema for this example is:
  124. </para>
  125. <programlisting language="sql"><![CDATA[
  126. CREATE TABLE IF NOT EXISTS `zfbugs` (
  127. `bug_id` int(11) NOT NULL auto_increment,
  128. `bug_description` varchar(100) default NULL,
  129. `bug_status` varchar(20) default NULL,
  130. `created_on` datetime default NULL,
  131. `updated_on` datetime default NULL,
  132. `reported_by` varchar(100) default NULL,
  133. `assigned_to` varchar(100) default NULL,
  134. `verified_by` varchar(100) default NULL,
  135. PRIMARY KEY (`bug_id`)
  136. ) ENGINE=InnoDB AUTO_INCREMENT=1 ;
  137. ]]></programlisting>
  138. </sect3>
  139. <sect3 id="zend.test.phpunit.db.quickstart.initial-tests">
  140. <title>A few initial database tests</title>
  141. <para>
  142. Now that we have implemented the two required abstract methods of the
  143. <classname>Zend_Test_PHPUnit_DatabaseTestCase</classname> and specified the seed
  144. database content, which will be re-created for each new test, we can go about to make
  145. our first assertion. This will be a test to insert a new bug.
  146. </para>
  147. <programlisting language="php"><![CDATA[
  148. class BugsTest extends Zend_Test_PHPUnit_DatabaseTestCase
  149. {
  150. public function testBugInsertedIntoDatabase()
  151. {
  152. $bugsTable = new Bugs();
  153. $data = array(
  154. 'created_on' => '2007-03-22 00:00:00',
  155. 'updated_on' => '2007-03-22 00:00:00',
  156. 'bug_description' => 'Something wrong',
  157. 'bug_status' => 'NEW',
  158. 'reported_by' => 'garfield',
  159. 'verified_by' => 'garfield',
  160. 'assigned_to' => 'mmouse',
  161. );
  162. $bugsTable->insert($data);
  163. $ds = new Zend_Test_PHPUnit_Db_DataSet_QueryDataSet(
  164. $this->getConnection()
  165. );
  166. $ds->addTable('zfbugs', 'SELECT * FROM zfbugs');
  167. $this->assertDataSetsEqual(
  168. $this->createFlatXmlDataSet(dirname(__FILE__)
  169. . "/_files/bugsInsertIntoAssertion.xml"),
  170. $ds
  171. );
  172. }
  173. }
  174. ]]></programlisting>
  175. <para>
  176. Now up to the <methodname>$bugsTable->insert($data);</methodname> everything looks
  177. familiar. The lines after that contain the assertion methodname. We want to verify
  178. that after inserting the new bug the database has been updated correctly with the
  179. given data. For this we create a
  180. <classname>Zend_Test_PHPUnit_Db_DataSet_QueryDataSet</classname> instance and give
  181. it a database connection. We will then tell this dataset that it contains a table
  182. "zfbugs" which is given by an <acronym>SQL</acronym> statement. This current/actual
  183. state of the database is compared to the expected database state which is contained in
  184. another <acronym>XML</acronym> file "bugsInsertIntoAssertions.xml". This
  185. <acronym>XML</acronym> file is a slight deviation from the one given above and contains
  186. another row with the expected data:
  187. </para>
  188. <programlisting language="xml"><![CDATA[
  189. <?xml version="1.0" encoding="UTF-8" ?>
  190. <dataset>
  191. <!-- previous 4 rows -->
  192. <zfbugs bug_id="5" bug_description="Something wrong" bug_status="NEW"
  193. created_on="2007-03-22 00:00:00" updated_on="2007-03-22 00:00:00"
  194. reported_by="garfield" assigned_to="mmouse" verified_by="garfield" />
  195. </dataset>
  196. ]]></programlisting>
  197. <para>
  198. There are other ways to assert that the current database state equals an expected
  199. state. The "Bugs" table in the example already knows a lot about its inner state, so
  200. why not use this to our advantage? The next example will assert that deleting from
  201. the database is possible:
  202. </para>
  203. <programlisting language="php"><![CDATA[
  204. class BugsTest extends Zend_Test_PHPUnit_DatabaseTestCase
  205. {
  206. public function testBugDelete()
  207. {
  208. $bugsTable = new Bugs();
  209. $bugsTable->delete(
  210. $bugsTable->getAdapter()->quoteInto("bug_id = ?", 4)
  211. );
  212. $ds = new Zend_Test_PHPUnit_Db_DataSet_DbTableDataSet();
  213. $ds->addTable($bugsTable);
  214. $this->assertDataSetsEqual(
  215. $this->createFlatXmlDataSet(dirname(__FILE__)
  216. . "/_files/bugsDeleteAssertion.xml"),
  217. $ds
  218. );
  219. }
  220. }
  221. ]]></programlisting>
  222. <para>
  223. We have created a <classname>Zend_Test_PHPUnit_Db_DataSet_DbTableDataSet</classname>
  224. dataset here, which takes any <classname>Zend_Db_Table_Abstract</classname> instance
  225. and adds it to the dataset with its table name, in this example "zfbugs". You could
  226. add several tables more if you wanted using the method
  227. <methodname>addTable()</methodname> if you want to check for expected database state
  228. in more than one table.
  229. </para>
  230. <para>
  231. Here we only have one table and check against an expected database state in
  232. "bugsDeleteAssertion.xml" which is the original seed dataset without the row with id
  233. 4.
  234. </para>
  235. <para>
  236. Since we have only checked that two specific tables (not datasets) are equal in the
  237. previous examples we should also look at how to assert that two tables are equal.
  238. Therefore we will add another test to our TestCase which verifies updating behaviour
  239. of a dataset.
  240. </para>
  241. <programlisting language="php"><![CDATA[
  242. class BugsTest extends Zend_Test_PHPUnit_DatabaseTestCase
  243. {
  244. public function testBugUpdate()
  245. {
  246. $bugsTable = new Bugs();
  247. $data = array(
  248. 'updated_on' => '2007-05-23',
  249. 'bug_status' => 'FIXED'
  250. );
  251. $where = $bugsTable->getAdapter()->quoteInto('bug_id = ?', 1);
  252. $bugsTable->update($data, $where);
  253. $rowset = $bugsTable->fetchAll();
  254. $ds = new Zend_Test_PHPUnit_Db_DataSet_DbRowset($rowset);
  255. $assertion = $this->createFlatXmlDataSet(
  256. dirname(__FILE__) . '/_files/bugsUpdateAssertion.xml'
  257. );
  258. $expectedRowsets = $assertion->getTable('zfbugs');
  259. $this->assertTablesEqual(
  260. $expectedRowsets, $ds
  261. );
  262. }
  263. }
  264. ]]></programlisting>
  265. <para>
  266. Here we create the current database state from a
  267. <classname>Zend_Db_Table_Rowset_Abstract</classname> instance in conjunction with
  268. the <methodname>Zend_Test_PHPUnit_Db_DataSet_DbRowset($rowset)</methodname> instance
  269. which creates an internal data-representation of the rowset. This can again be
  270. compared against another data-table by using the
  271. <methodname>$this->assertTablesEqual()</methodname> assertion.
  272. </para>
  273. </sect3>
  274. </sect2>