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

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.

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