Spec BDD with PHPSpec

Quality?

Quality

  • External – what matters most for the customer.
  • Internal – the maintainability of the source code.

Development Cycle

Refactoring

The process of restructuring existing code without changing external behavior.

TDD vs Spec BDD

Test

Specify

Test Method

Example

Assert

Expect

The difference is the language!

PHPUnit vs PHPSpec

$this->assertEquals(0, $result); // PHPUnit

$result->shoulBe(0);             // PHPSpec

It's not only about the language

$ phpunit CommandTest.php 
PHPUnit 3.7.28 by Sebastian Bergmann.

PHP Fatal error:  Class 'Command' not found 
in Tests/TestCommand.php on line 8
public function testCanAbortUpload()
{

    $transfer = $this->getMockedTransfer();
    $model = $this->getMockBuilder('Guzzle\Service\Resource\Model')
        ->disableOriginalConstructor()
        ->getMock();
    $command = $this->getMockBuilder('Guzzle\Service\Command\OperationCommand')
        ->disableOriginalConstructor()
        ->getMock();
    $command->expects($this->any())
        ->method('getResult')
        ->will($this->returnValue($model));
    $transfer->expects($this->any())
        ->method('getAbortCommand')
        ->will($this->returnValue($command));

    $transfer->abort();
    $this->assertTrue($this->readAttribute($transfer, 'stopped'));
}

I want tool that is

  • My friend
  • Fun to use
  • Does not get in the way

What is PHPSpec?

PHPSpec is a development tool, designed to help you achieve clean and working PHP code by using a technique derived from test-first development called (spec) behaviour driven development, or SpecBDD.

phpspec.net

Matchers

  • Identity
  • Comparison
  • Throw
  • Type
  • ObjectState
  • Count
  • Scalar
  • Inline

Identity

$this->getRating()->shouldBe(5);
$this->getTitle()->shouldBeEqualTo("Star Wars");
$this->getReleaseDate()->shouldReturn(233366400);

===

Comparison

$this->getRating()->shouldBeLike('5');

==

Throw

$this->shouldThrow('\InvalidArgumentException')->duringSetRating(-3);
$this->shouldThrow('\InvalidArgumentException')->during('setRating', array(-3));
$this->shouldThrow(new \InvalidArgumentException("Invalid rating"))->during('setRating', array(-3));

Type

$this->shouldHaveType('Movie');
$this->shouldReturnAnInstanceOf('Movie');
$this->shouldBeAnInstanceOf('Movie');
$this->shouldImplement('Movie');

Object State

$this->shouldBeAvailableOnCinemas();
$this->shouldHaveSoundtrack();

Count

$this->getItems()->shouldHaveCount(3);

Scalar

$this->getTitle()->shouldBeString();
$this->getPrice()->shouldBeFloat();
$this->getItems()->shouldBeArray();

Inline

class MovieSpec extends ObjectBehavior
{
    function it_should_have_some_specific_options_by_default()
    {
        $this->getOptions()->shouldHaveKey('username');
        $this->getOptions()->shouldHaveValue('diegoholiveira');
    }

    public function getMatchers()
    {
        return [
            'haveKey' => function($subject, $key) {
                return array_key_exists($key, $subject);
            },
            'haveValue' => function($subject, $value) {
                return in_array($value, $subject);
            },
        ];
    }
}

Formatters

  • progress
  • html
  • pretty
  • junit
  • dot

Stubs

$converter
    ->convert(80, 'USD')
    ->willReturn(106.54)
;

Mocks

$converter
    ->convert(80, 'USD')
    ->shouldBeCalled()
;

Let and let go

class ConverterSpec extends ObjectBehavior
{
    function let(ExchangeRate $exchangeRate)
    {
        $this->beConstructedWith($exchangeRate);
    }

    function letgo()
    {
        // release any resource
    }
}

Templates

  • specification
  • class
  • method

Templates

  1. {project_directory}/.phpspec/{template_name}.tpl
  2. {home_directory}/.phpspec/{template_name}.tpl
  3. Use the default template

Templates

  • %filepath% the file path of the class
  • %name% the class name
  • %namespace% the class namespace
  • %namespace_block% the formatted class namespace

Templates

<?php

/**
 * This file is part of the T-Day talk.
 *
 * @author PHPSpec developers
 */

namespace %namespace%;

class %name%
{
}

.phpspec/class.tpl

Spec BDD with PHPSpec

By Saša Stamenković

Spec BDD with PHPSpec

  • 4,157