Search icon
Subscription
0
Cart icon
Close icon
You have no products in your basket yet
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Instant Hands-on Testing with PHPUnit How-to

You're reading from  Instant Hands-on Testing with PHPUnit How-to

Product type Book
Published in May 2013
Publisher Packt
ISBN-13 9781782169581
Pages 82 pages
Edition 1st Edition
Languages
Author (1):
Michael Lively Michael Lively
Profile icon Michael Lively

Generating tests from code (Advanced)


When you are writing tests for untested legacy code or you do not employ a test-driven development methodology you will frequently find yourself needing to create test cases for already existing classes. PHPUnit has built-in capability to create skeletons for existing classes. This functionality can help you build up your test suite very quickly.

Using this functionality to test legacy code can be very effective. It will create several tests that are marked as incomplete which can be used to help you determine how far away you are from having coverage in all of your class methods.

Getting ready

The skeleton functionality is an add-on that must be installed to PHPUnit. It can be installed via PEAR using the phpunit/PHPUnit_SkeletonGenerator package.

In order for the preceding command to work you do need to make sure the auto_discover configuration is set to 1. If you get errors about unrecognized channels you can enable auto_discover with the sudo pear config-set auto_discover 1 command.

If you are using Composer in your project, it is worth noting that there is not a composer package for the Skeleton Generator. You will have to install it manually.

How to do it...

  1. Run phpunit-skelgen --test -- Player src/Player.php PlayerTest test/PlayerTest.php in the project folder.

  2. Open the test/PlayerTest.php file. You will see the following code in that file:

    <?php
    /**
     * Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2013-01-01 at 23:02:55.
     */
    class PlayerTest extends PHPUnit_Framework_TestCase
    {
        /**
         * @var Player
         */
        protected $object;
    
        /**
         * Sets up the fixture, for example, opens a network connection.
         * This method is called before a test is executed.
         */
        protected function setUp()
        {
            $this->object = new Player;
        }
    
        /**
         * Tears down the fixture, for example, closes a network connection.
         * This method is called after a test is executed.
         */
        protected function tearDown()
        {
        }
    
        /**
         * @covers Player::getName
         * @todo   Implement testGetName().
         */
        public function testGetName()
        {
            // Remove the following lines when you implement this test.
            $this->markTestIncomplete(
              'This test has not been implemented yet.'
            );
        }
    
        /**
         * @covers Player::drawCard
         * @todo   Implement testDrawCard().
         */
        public function testDrawCard()
        {
            // Remove the following lines when you implement this test.
            $this->markTestIncomplete(
              'This test has not been implemented yet.'
            );
        }
        //...Rest of tests
    }

How it works...

The phpunit-skelgen command takes up to four parameters. The format of the command is phpunit-skelgen --test -- <Class Name> <Class File Path> <Test Class Name> <Test Class File Path>. The class names should be fully qualified class names including the namespace. There are variants of this command that you can use that will look for the file based on the name; however, being as explicit with this command as possible will give you better, more predictable results.

One thing that you will notice is that the skeleton does not properly invoke your constructor. You have to handle this piece of the test case manually. Once that is done you will see that all of the tests return Incomplete as the status. As you fill out the tests they will change from incomplete tests to passing tests.

There's more...

The PHPUnit Skeleton Generator is a very powerful command. So far we have barely scratched the surface of how you can use it. When you combine it with PHPDoc annotations you can generate some of the actual test code as opposed to incomplete stubs. You can also use the PHPUnit Skeleton Generator to assist in test-driven development.

Using @assert to generate additional code

You can give the generator hints as to what test code should be created using the @assert annotation. These annotations should be added directly to the code that you will be testing. The format of the annotation is @assert (arg1, arg2, …, argn) operation result. The operation can be any logical comparison such as ==, !=, <, or > as well as the throws string. The logical comparisons are obvious in their use. The == operation is the equivalent to the PHPUnit assertEquals() method. The throws operator is equivalent to the @expectedException annotation.

You can see this in action by adding the following comment to the isInMatchingSet() method in src/Card.php:

  /**
   * Returns true if the given card is in the same set
   * @param Card $card
   * @return bool
   * @assert (new Card(3, 'h'), new Card(3, 's')) == true
   * @assert (new Card(4, 'h'), new Card(3, 's')) == false
   */
  public function isInMatchingSet(Card $card)

When you run the phpunit-skelgen --test -- Card src/Card.php CardTest2 test/CardTest2.php command and look at the generated test/CardTest2.php file you will now see the following test method:

    /**
     * Generated from @assert (new Card(3, 'h'), new Card(3, 's')) == true.
     *
     * @covers Card::isInMatchingSet
     */
    public function testIsInMatchingSet()
    {
        $this->assertTrue(
          $this->object->isInMatchingSet(new Card(3, 'h'), new Card(3, 's'))
        );
    }

    /**
     * Generated from @assert (new Card(4, 'h'), new Card(3, 's')) == false.
     *
     * @covers Card::isInMatchingSet
     */
    public function testIsInMatchingSet2()
    {
        $this->assertFalse(
          $this->object->isInMatchingSet(new Card(4, 'h'), new Card(3, 's'))
        );
    }

You'll notice that for each @assert annotation, a corresponding test method was created.

Using the Skeleton Generator for test-driven development

The Skeleton Generator can also be used when employing a test-driven development methodology. The examples so far have been focused on creating tests based on written code. This is contradictory to the test-driven development methodology. However, you can create code from tests just as easily as you can create tests from code. When you run phpunit-skelgen --class – CardTest test/CardTest.php from the project directory you will see that it creates a new Card class in src/Card.php. It even stubs the methods that it detects based on the test methods you wrote.

<?php
/**
 * Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2013-02-11 at 00:12:00.
 */
class Card
{
    /**
     * @todo Implement getNumber().
     */
    public function getNumber()
    {
        // Remove the following line when you implement this method.
        throw new RuntimeException('Not yet implemented.');
    }

    /**
     * @todo Implement getSuit().
     */
    public function getSuit()
    {
        // Remove the following line when you implement this method.
        throw new RuntimeException('Not yet implemented.');
    }

    /**
     * @todo Implement isInMatchingSet().
     */
    public function isInMatchingSet()
    {
        // Remove the following line when you implement this method.
        throw new RuntimeException('Not yet implemented.');
    }
}
arrow left Previous Chapter
You have been reading a chapter from
Instant Hands-on Testing with PHPUnit How-to
Published in: May 2013 Publisher: Packt ISBN-13: 9781782169581
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime}