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 data providers (Intermediate)


Data providers are a great way to test many different variants of a single method call quickly. When you have a method that is responsible for applying an algorithm to the method arguments and come up with a predictable result then data providers are a great option.

How to do it...

Modify the contents of test/CardTest.php to the following:

<?php
class CardTest extends PHPUnit_Framework_TestCase
{
  private $card;
  public function setUp()
  {
    $this->card = new Card('4', 'spades');
  }
  public function testGetNumber()
  {
    $actualNumber = $this->card->getNumber();
    $this->assertEquals(4, $actualNumber, 'Number should be <4>');
  }
  public function testGetSuit()
  {
    $actualSuit = $this->card->getSuit();
    $this->assertEquals('spades', $actualSuit, 'Suit should be <spades>');
  }
  public function matchingCardDataProvider()
  {
    return array(
      array(new Card('4', 'hearts'), true, 'should match'),
      array(new Card('5', 'hearts'), false, 'should not match')
    );
  }

  /**
   * @dataProvider matchingCardDataProvider
   */
  public function testIsInMatchingSet(Card $matchingCard, $expected, $msg)
  {
    $this->assertEquals($expected, $this->card->isInMatchingSet($matchingCard),
        "<{$this->card->getNumber()} of {$this->card->getSuit()}> {$msg} "
        . "<{$matchingCard->getNumber()} of {$matchingCard->getSuit()}>");
  }
}

How it works...

The new matchingCardDataProvider() method is our data provider. It should return an array containing multiple arrays of arguments to pass into a test method. The method does need to be public as it actually gets called from outside the test case. Also, the method does not have to be static, as you do not have reliable access to any variable you should treat the method as though it were static.

You then need to assign the data provider to one of your test methods. This is done using the @dataProvider annotation. In this example, the annotation is assigned to the testIsInMatchingSet() method. You will notice that this method has three parameters. This is exactly the same number of items there are in each sub-array returned by matchingCardDataProvider().

The three parameters in this example are the arguments provided for isInMatchingSet(), an expected value, as well as part of the assertion failure message. When using data providers you can use the Don't Repeat Yourself (DRY) principal very effectively to reduce the amount of code you have to write for each test. However, this does need to be balanced with readability. If you reduce the amount of code that has to be written, but someone else can't understand what the test is doing then the effectiveness and maintainability of the test is actually reduced.

Identifying test failures

You may be wondering how to identify which data set failed while using the data providers. Fortunately, PHPUnit takes care of this for you. Modify the matchingCardDataProvider() method to return a row that will force the test to fail.

public function matchingCardDataProvider()
{
  return array(
    array(new Card('4', 'hearts'), true, 'should match'),
    array(new Card('5', 'hearts'), false, 'should not match'),
    array(new Card('4', 'clubs'), false, 'should not match')
  );
}

Then, run the unit test suite and you will see the following:

As you can see it tells you the index of the data set along with the actual parameters passed as a part of that data set.

This can be improved even further by providing keys to the array that your data provider returns. Try using the following data provider:

public function matchingCardDataProvider()
{
  return array(
    '4 of Hearts' => array(new Card('4', 'hearts'), true, 'should match'),
    '5 of Hearts' => array(new Card('5', 'hearts'), false, 'should not match'),
    '4 of Clubs' => array(new Card('4', 'clubs'), false, 'should not match')
  );
}

Run the tests again to see the following output:

As you can see, you can utilize data providers to not only consolidate your code, but you can also make it very easy to isolate the data set you have problems with.

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