Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHPUnit setup before running first test and tear down after running last test

Tags:

I am trying to implement a Django like test utility for a php application using PHPUnit. By Django like, I mean a separate test db is created from the main database before running the first test and it's dropped after running the last test. The test db needs to be created only once even if many test cases are run at a time.

For this, I took the following approach -

I defined a custom test suite class so that I can write the code for creating and dropping the db in it's setup and teardown methods and then use this class to run the tests as follows

$ phpunit MyTestSuite 

MyTestSuite defines a static method named suite where I just use glob and add tests to the testsuite as follows

public static function suite() {     $suite = new MyTestSuite();      foreach (glob('./tests/*Test.php') as $tc) {         require_once $tc;         $suite->addTestSuite(basename($tc, '.php'));     }      return $suite; } 

All Test Case classes extend from a subclass of PHPUnit_Framework_TestCase and the setup and teardown methods of this class take care of loading and clearing initial data from json fixture files.

Now as the no. of tests are increasing, I need to run only a selected tests at a time. But since I am already loading tests using a test suite, the --filter option cannot be used. This makes me feel that this approach may not have been the correct one.

So my question is, what is the correct approach to do something before running the first test and after running the last test irrespective of how PHPUnit finds them ?

PS: I am not using PHPUnit_Extensions_Database_TestCase but my own implementation of creating, populating and dropping the db.

like image 464
naiquevin Avatar asked Jun 05 '12 11:06

naiquevin


People also ask

What is PHPUnit setUp?

PHPUnit supports sharing the setup code. Before a test method is run, a template method called setUp() is invoked. setUp() is where you create the objects against which you will test. Once the test method has finished running, whether it succeeded or failed, another template method called tearDown() is invoked.

How do I run a PHPUnit test?

How to Run Tests in PHPUnit. You can run all the tests in a directory using the PHPUnit binary installed in your vendor folder. You can also run a single test by providing the path to the test file. You use the --verbose flag to get more information on the test status.

What is PHPUnit testing?

PHPUnit is a unit testing framework for the PHP programming language. It is an instance of the xUnit architecture for unit testing frameworks that originated with SUnit and became popular with JUnit. PHPUnit was created by Sebastian Bergmann and its development is hosted on GitHub.

What are fixtures in PHP?

Doctrine fixtures is a PHP library that loads a set of data fixtures fully written in PHP. Creating a fixtures file is simple, you only have to create a PHP class that implements the FixtureInterface and instantiate as many object as you want to store.


2 Answers

I recently encountered something where I needed to solve the very same issue. I tried Edorian's answer with the __destruct method of a custom class, but it seemed to be run at the end of every test rather than at the conclusion of all tests.

Instead of using a special class in my bootstrap.php file, I utilized PHP's register_shutdown_function function to handle database cleanup after the conclusion of all my tests, and it seemed to work perfectly.

Here's an example of what I had in my bootstrap.php file

register_shutdown_function(function(){    some_db_cleanup_methods(); }); 
like image 84
Ian Hunter Avatar answered Sep 28 '22 12:09

Ian Hunter


My two spontaneous ideas that don't use "Test Suites". One that does is at the bottom.

Test Listener

Using PHPUnits test listeners you could do a

  public function startTestSuite(PHPUnit_Framework_TestSuite $suite)   {        if($suite->getName() == "yourDBTests") { // set up db   }    public function endTestSuite(PHPUnit_Framework_TestSuite $suite)   {        if($suite->getName() == "yourDBTests") { // tear down db   } 

You can define all your DB tests in a testsuite in the xml configuration file like shown in the docs

<phpunit>   <testsuites>     <testsuite name="db">       <dir>/tests/db/</dir>     </testsuite>     <testsuite name="unit">       <dir>/tests/unit/</dir>     </testsuite>   </testsuites> </phpunit> 

Bootstrap

Using phpunits bootstrap file you could create a class that creates the DB and tears it down in it's own __destruct method when the process ends.

Putting the reference to the object in some global scope would ensure the object only gets destructured at the end off all tests. ( As @beanland pointed out: Using register_shutdown_function() makes a whole lot more sense!)


Using Test suites:

http://www.phpunit.de/manual/3.2/en/organizing-test-suites.html shows:

<?php  class MySuite extends PHPUnit_Framework_TestSuite {     public static function suite()     {         return new MySuite('MyTest');     }      protected function setUp()     {         print "\nMySuite::setUp()";     }      protected function tearDown()     {         print "\nMySuite::tearDown()";     } }  class MyTest extends PHPUnit_Framework_TestCase {     public function testWorks() {         $this->assertTrue(true);     } } 

this works well in PHPUnit 3.6 and will work in 3.7. It's not in the current docs as the "Test suite classes" are somewhat deprecated/discouraged but they are going to be around for quite some time.


Note that tearing down and setting up the whole db for each test case can be quite useful to fight inter-test-dependencies but if you don't run the tests in memory (like sqlite memory) the speed might not be worth it.

like image 45
edorian Avatar answered Sep 28 '22 13:09

edorian