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 abstract classes (Intermediate)


When we were discussing mock objects the concept of partial mocks was introduced. One common use of partial mocks is to test abstract classes. Abstract classes can't be tested directly as by definition they cannot be instantiated. You can always create an extension of the abstract class just for testing. However, PHPUnit provides functionality to very easily mock abstract classes so that only the abstract methods get mocked. All other functions will execute normally.

How to do it...

In src/Player.php is a Player class shown as follows:

<?php
abstract class Player
{
  // ...

  public function requestCard()
  {
    $cardNumber = $this->chooseCardNumber();

    if (!$this->hasCard($cardNumber))
    {
      throw new RuntimeException('Invalid card chosen by player');
    }

    return $cardNumber;
  }

  abstract protected function chooseCardNumber();

  // ...
}

The corresponding test can be placed in test/PlayerTest.php to test the abstract nature of the class.

<?php
class PlayerTest extends PHPUnit_Framework_TestCase
{
private $player;
  private $hand;

  public function setUp()
  {
    $this->hand = new CardCollection();
    $this->hand->addCard(new Card('A', 'Spades'));
    $this->player = $this->getMockForAbstractClass('Player', array('John Smith', $this->hand));
  }

  public function testRequestCardCallsChooseCardNumber()
  {
    $this->player->expects($this->once())
      ->method('chooseCardNumber')
      ->will($this->returnValue('A'));

    $this->assertEquals('A', $this->player->requestCard());
  }
}

How it works...

The PHPUnit method getMockForAbstractClass() can be used to generate a partial mock where only the abstract methods of a given class are overridden. The argument list for getMockForAbstractClass() is similar to the argument list for getMock(). The big difference is that the list of methods to mock is moved from being the second parameter to being the last parameter. By default getMockForAbstractClass() will mock only the abstract methods of the class. If you find yourself needing to override this functionality then you should just use getMock() instead.

In this example, the Player class is being mocked with a player name and a CardCollection object is being passed to the Player instance's constructor. The testRequestCardCallsChooseCardNumber() method is assuring that the Player::chooseCardNumber() method is called as a part of Player::requestCard() and is then ensuring that the value returned by chooseCardNumber() is subsequently returned by requestCard().

You could use getMock() for this instead. The setUp() method could be rewritten to use getMock() to set up the partial mock.

public function setUp()
{
  $this->hand = new CardCollection();
  $this->hand->addCard(new Card('A', 'Spades'));
  $this->player = $this->getMock('Player', array('chooseCardNumber'), array('John Smith', $this->hand));
}

The advantage of using getMockForAbstractClass() is that you do not have to add to the mocked method list (the second parameter of getMock()) every time you add a new abstract method to the class. It also keeps the test significantly more concise.

Abstract classes in Phake

Phake also provides a function that assists in testing abstract classes. Phake::partialMock() works in a similar fashion to the PHPUnit counterpart.

<?php
class PhakePlayerTest extends PHPUnit_Framework_TestCase
{
private $player;
  private $hand;

  public function setUp()
  {
    $this->hand = new CardCollection();
    $this->hand->addCard(new Card('A', 'Spades'));
    $this->player = Phake::partialMock('Player', 'John Smith', $this->hand);
  }

  public function testRequestCardCallsChooseCardNumber()
  {
    Phake::when($this->player)->chooseCardNumber()->thenReturn('A');

    $this->assertEquals('A', $this->player->requestCard());

    Phake::verify($this->player)->chooseCardNumber();
  }
}

The Phake::partialMock() method accepts the class name as the first parameter. The remaining parameters will be used in the constructor of the mock object. This method works in mostly the same way as getMockForAbstractClass(). It creates a mock that will call the original method for any non-abstract method.

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