This project is no longer maintained and has been archived. |
Unit Testing
Doctrine is programmatically tested using UnitTests. You can read more about unit testing here on Wikipedia.
Running tests
In order to run the tests that come with doctrine you need to check out the entire project, not just the lib folder.
$ svn co http://svn.doctrine-project.org/branches/1.2 /path/to/co/doctrine
Now change directory to the checked out copy of doctrine.
$ cd /path/to/co/doctrine
You should see the following files and directories listed.
CHANGELOG
COPYRIGHT
lib/
LICENSE
package.xml
tests/
tools/
vendor/
It is not uncommon for the test suite to have fails that we are aware of. Often Doctrine will have test cases for bugs or enhancement requests that cannot be committed until later versions. Or we simply don't have a fix for the issue yet and the test remains failing. You can ask on the mailing list or in IRC for how many fails should be expected in each version of Doctrine. |
CLI
To run tests on the command line, you must have php-cli installed.
Navigate to the /path/to/co/doctrine/tests
folder and execute the
run.php
script:
$ cd /path/to/co/doctrine/tests
$ php run.php
This will print out a progress bar as it is running all the unit tests. When it is finished it will report to you what has passed and failed.
The CLI has several options available for running specific tests, groups of tests or filtering tests against class names of test suites. Run the following command to check out these options.
$ php run.php -help
You can run an individual group of tests like this:
$ php run.php --group data_dict
Browser
You can run the unit tests in the browser by navigating to
doctrine/tests/run.php
. Options can be set through _GET
variables.
For example:
- http://localhost/doctrine/tests/run.php
- http://localhost/doctrine/tests/run.php?filter=Limit&group[]=query&group[]=record
Please note that test results may very depending on your
environment. For example if |
Writing Tests
When writing your test case, you can copy TemplateTestCase.php
to
start off. Here is a sample test case:
class Doctrine_Sample_TestCase extends Doctrine_UnitTestCase
{
public function prepareTables()
{
$this->tables[] = "MyModel1";
$this->tables[] = "MyModel2";
parent::prepareTables();
}
public function prepareData()
{
$this->myModel = new MyModel1();
//$this->myModel->save();
}
public function testInit()
{
}
// This produces a failing test
public function testTest()
{
$this->assertTrue( $this->myModel->exists() );
$this->assertEqual( 0, 1 );
$this->assertIdentical( 0, '0' );
$this->assertNotEqual( 1, 2 );
$this->assertTrue( ( 5 < 1 ) );
$this->assertFalse( (1 > 2 ) );
}
}
class Model1 extends Doctrine_Record
{
}
class Model2 extends Doctrine_Record
{
}
The model definitions can be included directly in the test
case file or they can be put in
|
Once you are finished writing your test be sure to add it to run.php
like the following.
$ test->addTestCase( new Doctrine_Sample_TestCase() );
Now when you execute run.php you will see the new failure reported to you.
Ticket Tests
In Doctrine it is common practice to commit a failing test case for each
individual ticket that is reported in trac. These test cases are
automatically added to run.php by reading all test case files found in
the /path/to/co/doctrine/tests/Ticket/
folder.
You can create a new ticket test case easily from the CLI:
$ php run.php --ticket 9999
If the ticket number 9999 doesn't already exist then the blank test case
class will be generated for you at /path/to/co/doctrine/tests/Ticket/9999TestCase.php
.
class Doctrine_Ticket_9999_TestCase extends Doctrine_UnitTestCase
{
}
Methods for testing
Assert Equal
// ...
public function test1Equals1()
{
$this->assertEqual( 1, 1 );
}
// ...
Assert Not Equal
// ...
public function test1DoesNotEqual2()
{
$this->assertNotEqual( 1, 2 );
}
// ...
Assert Identical
The assertIdentical()
method is the same as the assertEqual()
except that its logic is stricter and uses the ===
for comparing the
two values.
// ...
public function testAssertIdentical()
{
$this->assertIdentical( 1, '1' );
}
// ...
The above test would fail obviously because the first argument is the number 1 casted as PHP type integer and the second argument is the number 1 casted as PHP type string. |
Assert True
// ...
public function testAssertTrue()
{
$this->assertTrue( 5 > 2 );
}
// ...
Assert False
// ...
public function testAssertFalse()
{
$this->assertFalse( 5 < 2 );
}
// ...
Mock Drivers
Doctrine uses mock drivers for all drivers other than sqlite. The following code snippet shows you how to use mock drivers:
class Doctrine_Sample_TestCase extends Doctrine_UnitTestCase
{
public function testInit()
{
$this->dbh = new Doctrine_Adapter_Mock( 'oracle' );
$this->conn = Doctrine_Manager::getInstance()->openConnection( $this->dbh );
}
}
Now when you execute queries they won't actually be executed against a real database. Instead they will be collected in an array and you will be able to analyze the queries that were executed and make test assertions against them.
class Doctrine_Sample_TestCase extends Doctrine_UnitTestCase
{
// ...
public function testMockDriver()
{
$user = new User();
$user->username = 'jwage';
$user->password = 'changeme';
$user->save();
$sql = $this->dbh->getAll();
// print the sql array to find the query you're looking for
// print_r( $sql );
$this->assertEqual( $sql[0], 'INSERT INTO user (username, password) VALUES (?, ?)' );
}
}
Test Class Guidelines
Every class should have at least one TestCase equivalent and they should inherit Doctrine_UnitTestCase. Test classes should refer to a class or an aspect of a class, and they should be named accordingly.
Some examples:
- Doctrine_Record_TestCase is a good name because it refers to the Doctrine_Record class
- Doctrine_Record_State_TestCase is also good, because it refers to the state aspect of the Doctrine_Record class.
- Doctrine_PrimaryKey_TestCase is a bad name, because it's too generic.
Test Method Guidelines
Methods should support agile documentation and should be named so that if it fails, it is obvious what failed. They should also give information of the system they test
For example the method test name
Doctrine_Export_Pgsql_TestCase::testCreateTableSupportsAutoincPks()
is a good name.
Test method names can be long, but the method content should not be. If you need several assert-calls, divide the method into smaller methods. There should never be assertions within any loops, and rarely within functions.
Commonly used testing method naming convention
|
Conclusion
Unit testing in a piece of software like Doctrine is so incredible important. Without it, it would be impossible to know if a change we make has any kind of negative affect on existing working use cases. With our collection of unit tests we can be sure that the changes we make won't break existing functionality.
Now lets move on to learn about how we can Improving Performance when using Doctrine.