Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Instant Hands-on Testing with PHPUnit How-to

You're reading from   Instant Hands-on Testing with PHPUnit How-to A practical guide to getting started with PHPUnit to improve code quality

Arrow left icon
Product type Paperback
Published in May 2013
Publisher Packt
ISBN-13 9781782169581
Length 82 pages
Edition 1st Edition
Languages
Arrow right icon
Author (1):
Arrow left icon
Michael Lively Michael Lively
Author Profile Icon Michael Lively
Michael Lively
Arrow right icon
View More author details
Toc

Using test dependencies (Advanced)


When you begin writing tests for one of your classes you may notice that when one aspect of functionality for your class breaks, many tests fail. Quite often a method of a class will have some preconditions that must be true for it to behave properly in a given situation. A classic example of this is a stack. If you cannot construct a stack properly then any further tests against that stack are most likely going to fail.

You can use PHPUnit's test dependency feature to help with this. When you indicate that one test is dependent on another test, PHPUnit will skip the dependent test whenever its dependencies do not successfully pass. Test dependencies also allow you to enable producer-consumer relationships into your test suites. One test case will "produce" the input for another test case to "consume".

We will take a look at how test dependencies can work by writing a test for our CardCollection class that looks at how cards are added to the deck.

How to do it...

Place the following code to the test/CardCollection.php file:

<?php
class CardCollectionTest extends PHPUnit_Framework_TestCase
{
  private $cardCollection;

  public function setUp()
  {
    $this->cardCollection = new CardCollection();
  }

  public function testCountOnEmpty()
  {
    $this->assertEquals(0, $this->cardCollection->count());
  }

  /**
   * @depends testCountOnEmpty
   */
  public function testAddCard()
  {
    $this->cardCollection->addCard(new Card('A', 'Spades'));
    $this->cardCollection->addCard(new Card('2', 'Spades'));

    $this->assertEquals(2, $this->cardCollection->count());

    return $this->cardCollection;
  }

  /**
   * @depends testAddCard
   */
  public function testGetTopCard(CardCollection $cardCollection)
  {
    $card = $cardCollection->getTopCard();

    $this->assertEquals(new Card('2', 'Spades'), $card);
  }
}

How it works...

In your new file you have two test methods using a @depends annotation. This is the annotation that enables PHPUnit's test dependency functionality. This annotation, essentially, tells PHPUnit that you do not want to run the following test unless the test referenced in the @depends annotation has passed. If this test has not passed then the following test will be skipped. If for some reason the CardCollection::count() method was not running properly and caused the testCountOnEmpty() test to fail then testAddCard() would be skipped. This can be easily seen by breaking the testCountOnEmpty() test on purpose by inserting $this|fail('testing @depends') in the test and rerunning your tests.

Another interesting aspect of the @depends annotation is the producer-consumer aspect of it. Whenever you mark a test with the @depends annotation the return value from the test specified in the annotation will be provided as the argument to the test being annotated. This is what is happening in the testGetTopCard() method. The testAddCard() method returns the card collection being tested. This value then persists for any test that depends on this method. As soon as we annotated testGetTopCard() with @depends testGetTopCard, PHPUnit is triggered to pass the populated card collection as the first parameter.

This does a couple things for you. It doesn't bother to try and pull the top card if it appears that addCard() is not working. It also prevents you from having to repeat the code necessary to populate your card collection.

Another thing to note is that the @depends annotations always reference a test above the annotation. The @depends annotation never influences the order of tests. Tests will always be run from the top of the file to the bottom of the file. If the @depends annotation references a method below the annotation it will simply skip the test as the dependency has not yet passed.

Multiple test dependencies

You can add multiple @depends annotations to a single test. PHPUnit will then check to ensure that all of the tests specified have passed before running a given test. If the dependencies also return values, they will all be accessible as arguments in the order they are specified. The following code shows how this works:

<?php
class DependencyTest extends PHPUnit_Framework_TestCase
{

  public function test1()
  {
    $this->assertTrue(true);
    return 1;
  }

  public function test2()
  {
    $this->assertTrue(true);
    return 2;
  }

  public function test3()
  {
    $this->assertTrue(true);
    return 3;
  }

  /**
   * @depends test1
   * @depends test2
   * @depends test3
   */
  public function testDependencies($arg1, $arg2, $arg3)
  {
    $this->assertEquals(1, $arg1);
    $this->assertEquals(2, $arg2);
    $this->assertEquals(3, $arg3);
  }
}

Multiple dependent tests

You can also have the same test referenced by @depends multiple times. You do need to be very careful when doing this. Copies are not made of any objects returned. So if you modify the object in any way in the first dependent test, those modifications will also be present in the second dependent test. This can be seen in the following code:

<?php
class DependencyTest extends PHPUnit_Framework_TestCase
{

  public function testCreateStdClass()
  {
    $obj = new stdClass();
    $obj->foo = 'bar';
    $this->assertTrue(true);
    return $obj;
  }

  /**
   * @depends testCreateStdClass
   */
  public function testDependency1($obj)
  {
    $this->assertEquals('bar', $obj->foo);
    $obj->foo = 'notbar';
  }

  /**
   * @depends testCreateStdClass
   */
  public function testDependency2($obj)
  {
    $this->assertEquals('notbar', $obj->foo);
  }
}
lock icon The rest of the chapter is locked
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 $19.99/month. Cancel anytime
Banner background image