Search icon
Subscription
0
Cart icon
Close icon
You have no products in your basket yet
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Instant Hands-on Testing with PHPUnit How-to

You're reading from  Instant Hands-on Testing with PHPUnit How-to

Product type Book
Published in May 2013
Publisher Packt
ISBN-13 9781782169581
Pages 82 pages
Edition 1st Edition
Languages
Author (1):
Michael Lively Michael Lively
Profile icon Michael Lively

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.

arrow left Previous Chapter
You have been reading a chapter from
Instant Hands-on Testing with PHPUnit How-to
Published in: May 2013 Publisher: Packt ISBN-13: 9781782169581
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 $15.99/month. Cancel anytime}