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