PHPUnit Skeleton Classes

25th July 2011

If you create classes in PHP then you should be unit testing them as much as you can. Setting up unit testing classes for your code can be time consuming and involve a bunch of copying and pasting. Thankfully, PHPUnit comes with a couple of helper functions that allow the creation of unit testing classes automatically, which can save a bit of copying and pasting.

As an example for this post I will use the following Spider class, which is part of some code I am working on at the moment to create a simple site spider in PHP.

  1. <?php
  2.  
  3. class Spider {
  4.  
  5. protected $queue = array();
  6. protected $urlLimit = 0;
  7.  
  8. /**
  9.   * Return a list of file types that are not to be downloaded.
  10.   *
  11.   * @return array The list of extensions to be excluded.
  12.   */
  13. public function excludedFileExtensions() {
  14. $extensions = array('pdf', 'exe', 'zip', 'css', 'js', 'gz', 'tar', 'mp3', 'wav', 'flv', 'doc', 'docx', 'odp', 'psd', 'jpg', 'jpeg', 'png', 'gif');
  15. return $extensions;
  16. }
  17.  
  18. /**
  19.   * Set the hard limit on the number of links to find on a site. Once this
  20.   * limit has been reached the loop will stop finding new pages.
  21.   *
  22.   * @param integer $limit The limit to be set.
  23.   *
  24.   * @return SitemapSpider The current object.
  25.   */
  26. public function setUrlLimit($limit) {
  27. $this->urlLimit = $limit;
  28. return $this;
  29. }
  30.  
  31. /**
  32.   * Add an item to the queue.
  33.   *
  34.   * @param string $url The URL
  35.   */
  36. public function enqueue($url) {
  37. $this->queue[$url] = $url;
  38. }
  39.  
  40. /**
  41.   * Tests to see if a given string is a URL.
  42.   *
  43.   * @param string $url The string to test.
  44.   *
  45.   * @return boolean True if string is URL, otherwise false.
  46.   */
  47. public function validUrl($url) {
  48. return preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i', $url);
  49. }
  50. }

Calling phpunit with the --skeleton-test flag will allow us to create unit testing classes for any class we stipulate. To do this with the above code, assuming that the class is in the file Spider.php, then we can run the following command.

phpunit --skeleton-test Spider Spider.php

The final parameter (Spider.php) is optional, but will only work if the file name is the same as the class name (with a .php extension at the end).

This creates a skeleton unit testing class ready for the actual unit tests to be implemented. Every method that was defined in the original class has its own test method in the unit testing class. Each test contains a call to markTestIncomplete(), which forces PHPUnit to skip the test and mark it as incomplete. When running the class through the command line this produces an "I" in the output. This class also includes the setUp() and tearDown() methods that are run before and after every test.

Here is the example unit testing class generated from the above command.

  1. <?php
  2.  
  3. require_once 'C:\path\to\class\Spider.php';
  4.  
  5. /**
  6.  * Test class for Spider.
  7.  * Generated by PHPUnit on 2011-07-22 at 16:44:10.
  8.  */
  9. class SpiderTest extends PHPUnit_Framework_TestCase
  10. {
  11. /**
  12.   * @var Spider
  13.   */
  14. protected $object;
  15.  
  16. /**
  17.   * Sets up the fixture, for example, opens a network connection.
  18.   * This method is called before a test is executed.
  19.   */
  20. protected function setUp()
  21. {
  22. $this->object = new Spider;
  23. }
  24.  
  25. /**
  26.   * Tears down the fixture, for example, closes a network connection.
  27.   * This method is called after a test is executed.
  28.   */
  29. protected function tearDown()
  30. {
  31. }
  32.  
  33. /**
  34.   * @todo Implement testExcludedFileExtensions().
  35.   */
  36. public function testExcludedFileExtensions()
  37. {
  38. // Remove the following lines when you implement this test.
  39. $this->markTestIncomplete(
  40. 'This test has not been implemented yet.'
  41. );
  42. }
  43.  
  44. /**
  45.   * @todo Implement testSetUrlLimit().
  46.   */
  47. public function testSetUrlLimit()
  48. {
  49. // Remove the following lines when you implement this test.
  50. $this->markTestIncomplete(
  51. 'This test has not been implemented yet.'
  52. );
  53. }
  54.  
  55. /**
  56.   * @todo Implement testEnqueue().
  57.   */
  58. public function testEnqueue()
  59. {
  60. // Remove the following lines when you implement this test.
  61. $this->markTestIncomplete(
  62. 'This test has not been implemented yet.'
  63. );
  64. }
  65.  
  66. /**
  67.   * @todo Implement testValidUrl().
  68.   */
  69. public function testValidUrl()
  70. {
  71. // Remove the following lines when you implement this test.
  72. $this->markTestIncomplete(
  73. 'This test has not been implemented yet.'
  74. );
  75. }
  76. }

I should point out here that the unit testing class that is generated is enough to get you started in testing the class, but shouldn't be relied upon as a complete testing framework. There is a fine line between testing methods and testing functionality, which is probably the basis of a post all of its own. The final unit testing class should look very different from the file generated here, but this is a good way to get up and running quickly.

It is also possible to generate classes from existing unit testing classes by using the --skeleton-class flag. This is the exact opposite from the method described above and is used if you create your unit testing classes first. To create a simple class from the existing SpiderTest unit testing class that we created above we would do the following.

As before, the final parameter can be omitted here, but only if the filename matches the class name. This creates a simple skeleton class that can be used as a code template. Below is a typical example of the output from the above command.

  1. <?php
  2. /**
  3.  * Generated by PHPUnit on 2011-07-22 at 17:10:51.
  4.  */
  5. class Spider
  6. {}
  7. ?>

One important thing to note here is that this can delete your existing class files if you aren't careful. The generated file above always has the same structure as this so any code you already have will be overwritten by this action.

Comments

Permalink
Good Work

Maha (Sat, 11/25/2017 - 19:12)

Add new comment

The content of this field is kept private and will not be shown publicly.