Book Image

Instant Hands-on Testing with PHPUnit How-to

By : Michael Lively
Book Image

Instant Hands-on Testing with PHPUnit How-to

By: Michael Lively

Overview of this book

No developer wants to accept the inherent difficulty of writing software as an excuse for not finding the bugs in our code before anyone else does. PHPUnit is a framework that was created to allow developers to solve that very problem. It provides a feature-rich environment with most of the tools necessary to provide adequate tests for any project. "Instant Hands-on Testing with PHPUnit How-to" provides a thorough overview of the functionality provided by the PHPUnit framework. It shows how the plethora of features in the framework can be used to write tests for real world projects to ensure they function and will continue to function in the ways that you expect. This book will show how you can set up the scaffolding necessary to run unit tests in your project with PHPUnit. It will walk you through the process of how to write a basic test and how to maintain your project's test suite. You will learn how to use some of the more advanced features of PHPUnit and then see how you can use mock objects to isolate the code you are testing. We will then discover how to create tests that verify your interaction with databases and even see how you can use PHPUnit to understand which code you are actually testing. At the end of the book you will have all of the basic understanding necessary to begin adding tests to your project. This book provides a great foundation for becoming a expert at writing unit tests.
Table of Contents (7 chapters)

Testing protected and private methods (Intermediate)


A common question of those that are getting started with unit testing is, how are protected and private methods tested? Protected and private methods are not uncommon and the desire to test the code in them should be natural. The confusion that arises from how to test these methods is created at least in part by the thought that they must be tested independently.

In the book Pragmatic Unit Testing, Dave Thomas and Andy Hunt had this to say:

In general, you don't want to break any encapsulation for the sake of testing (or as mom used to say, "don't expose your privates!"). Most of the time, you should be able to test a class by exercising its public methods. If there is significant functionality that is hidden behind private or protected access, that might be a warning sign that there's another class in there struggling to get out.

Using the public interface of your class is by far the best way to test protected and private methods. If you find yourself unable to do this, PHPUnit and PHP itself offer solutions to test these methods directly.

How to do it...

The following code in the CardCollection class is used to add a card to the collection:

<?php
class CardCollection implements IteratorAggregate
{
  // ...
  public function addCard(Card $card)
  {
    array_push($this->cards, $card);
  }
  // ...
}

The following test can be used to ensure the object state is modified accordingly:

<?php
class CardCollectionTest extends PHPUnit_Framework_TestCase
{
  // ...
  public function testAddCardAffectAttribute()
  {
    $card = new Card('A', 'Spades');
    $this->cardCollection->addCard($card);
    $this->assertAttributeEquals(array($card), 'cards', $this->cardCollection);
  }
  // ...
}

How it works...

This test shows how you can inspect the private or protected state of a given object. PHPUnit has a series of attribute assertions that you can use to test the value of any attribute on a class even if it has protected or private visibility. Whenever possible you should use the public interface of an object to test this; however, in the event that it is not possible, the attribute assertions can come in very handy. The assertAttributeEquals() method is similar to its non-attribute counterpart assertEquals(). However, instead of passing the value you are testing, you pass the name of the attribute you want to test as the second parameter and the object that attribute is set on as the third parameter. As always, the expected value is passed in as the first parameter.

PHPUnit contains attribute equivalents for the standard set of assertions. You can compare values, check contents of arrays, compare array counts, and so on. Anything you would typically do with a variable in a unit test can also be accomplished in attributes using the attribute assertions.

Private and protected methods

PHPUnit doesn't provide the same functionality above for private and protected methods. However, if you are using PHP 5.3.2 or higher you can use reflection to alter the visibility of the method you are trying to test.

In CliFormatter there is a private method, getCard(), that is used to format a given card into a readable string.

<?php
class CliFormatter
{
  // ...
  private function getCard(Card $card)
  {
    return $card->getNumber() . substr($card->getSuit(), 0, 1);
  }
  // ...
}

Using reflection we can expose this method and invoke it as a part of a test.

<?php
class CliFormatterTest extends PHPUnit_Framework_TestCase
{
  // ...
  public function testGetCard()
  {
    $method = new ReflectionMethod('CliFormatter', 'getCard');
    $method->setAccessible(true);

    $card = new Card('A', 'Spades');
    $this->assertEquals('AS', $method->invoke($this->formatter, $card));
  }
  // ...
}

The ReflectionMethod::setAccessible() method can be used to allow a method to be invoked. However, you must invoke that method using the ReflectionMethod::invoke() method. If we attempted to call $this|formatter|getCard() directly then it would fail. This does keep us from having to clean up the accessibility. Your client code will continue to work as you originally wrote it. You don't have to worry about the method continuing to be accessible.