Fun Driven Development with PHPSpec
Tags: php, programming, testing, tdd
Published: 2020-06-05 17:39:15

---
title: Fun Driven Development with PHPSpec
published: true
description: Have fun with BDD and PHPSpec!
tags: #php, #programming, #testing, #tdd
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/40o73tq1qzwraq9wjfrw.png
---

The first time I saw the abbreviation BDD I thought it was a miss-print of TDD (Test Driven Development), but it’s not. It stands for *Behaviour Driven Development* and it is a technique derived from TDD. The difference between the two is a bit nuanced and best felt when you start using some BDD tools. One such tool is [PHPSpec](http://www.phpspec.net/en/stable/)<span>. It will help you write better code and have fun in the process. Sounds good? Let’s give it a try!

## There is a dog

[Dogs](http://www.instagram.com/doggosdoingthings/?hl=hr) are fun so let's build a Dog game:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wkz0n5rngwdw6lz3oll5.png)

In PHPSpec you start by creating the specification first. It will describe the Dog class we are going to build:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/xtu6zoigcfckz32vj60s.png)

PHPSpec generates the specification file for us:

```php
<?php

namespace spec\App;

use App\Dog;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

class DogSpec extends ObjectBehavior
{
    function it_is_initializable()
    {
        $this->shouldHaveType(Dog::class);
    }
}
```

It doesn't say (describe) much at the moment - just that the class Dog should be initializable.

Let's run PHPSPec to see what happens.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/i1wf6vwb30yreqhchxom.png)

Whoa, that's a lot of pink! What's up with that? Well, this is how PHPSPec indicates that the code is broken (doesn't even run), which is different than it running but returning wrong results. It is also asking us to fix it by creating the missing Dog class for us. So we comply and we get this:

```php
<?php

namespace App;

class Dog
{
}
```

After creating the Dog class, it runs again and now we have our first spec passing giving us that green light all devs love so much.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/udmp99wnu00n43uzreg4.png)


## Dogs make sounds

As all dog owners will tell you, dogs bark, so let's add this behavior to our doggo:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dr3ilyoqgoe6alqn18ed.png)

We describe the desired behaviour in the spec class:

```php
<?php

# spec/App

class DogSpec extends ObjectBehavior
{
    // ...

    function it_should_make_a_sound()
    {
        $this->makeSound()->shouldBe('Vuf Vuf');
    }

}
```

I know. This looks a bit wired. We are calling the `makeSound` method but there is no such method in our spec class. And there won't be. The `$this` keyword in a spec class doesn't refer to the spec class itself, but to the class the spec is describing. In this case, `DogSpec` described the `Dog` class, so PHPSpec will try to call the `makeSound` method on the `Dog` class. (There is always one spec class per class).

Another wired thing is the `shouldBe` method chained to the `makeSound` method. This is what is called a **matcher** in PHPSpec and it's equivalent to PHPUnit's assertions (and there's a bunch of them). In this case, it will take the output of the `makeSound` method and check if it matches `Vuf Vuf`.

Now that we've straightened that out, we can run <span>PHPSpec</span> again:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/p1w1wc3cv7jxj7etsulr.png)

Since we don't have the `makeSound()` method on our Dog class yet, there's that purple color again and there's PHPSpec again being nice and helpful offering to create the method for us.

After creating the method it runs again and now we finally have some red color meaning the code works but not as expected.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/izejzc10robu9f0dlt4b.png)

Time to write some code and get us back to green!

```php
<?php

# src/App

class Dog
{
    public function makeSound(): string
    {
        return 'Vuf Vuf';
    }
}
```

# Stubs

Our object often time collaborate with other objects by asking them questions (and doing something with the answer). If we go back to our pet game, dogs are usually very happy to great people:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dr3ilyoqgoe6alqn18ed.png)

To describe this in our specification we'll need a **<span>stub</span>**:

```php
<?php

# spec/App

class DogSpec extends ObjectBehavior
{
    // ...

    function it_can_greet_a_person(Person $person)
    {
        $person->name()->willReturn('Mike');
        $this->greet($person)->shouldBe('Hello Mike, Vuf Vuf');
    }
}
```

Looking at this, you may be wondering where is some `createTestDouble()` method call? In PHPSpec you just inject classes/objects you need and PHPSpec will create test doubles out of them (using prophecy framework) so you can immediately configure them. Here, we are stating the person's class `name()` method will return `Mike` when called.

By now you can assume when we run PHPSpec it will offer to create the actual `Person` class for us, right?

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/2mgfvb97ywy93im73d3v.png)

But wait. It says "Would you like me to generate an **<span>interface</span>**". Why not a class? Hm, now that I think about it, dogs also like to greet other dogs not just humans, so maybe there is an abstraction here that we missed. Let's introduce an interface called `Named` and make our `Dog` class is dependent on an interface instead of a concrete class.

```php
<?php

# spec/App

class DogSpec extends ObjectBehavior
{
    // ...

    function it_can_greet_a_person(Named $named)
    {
        $named->name()->willReturn('Mike');
        $this->greet($named)->shouldBe('Hello Mike, Vuf Vuf');
    }
}
```

Now our <span>Dog</span> can greet any class that implements the `Named` interface. This design will make it easy to expand the list of earthlings our doggos can greet - just implement the `Named` interface. Thnx PHPSpec!

We can let PHPSpec make that interface and the greet method for us now

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/83xnnkemp0xiwjw6iqdn.png)

And now we can implement our greet method to get us back to green again:

```php
<?php

# src/App

class Dog
{
    public function makeSound()
    {
        return 'Vuf Vuf';
    }

    public function greet(Named $named)
    {
        return 'Hello ' . $named->name() . 'Vuf Vuf';
    }
}
```

# Mocks and Spies

Let's say for business reason, every time a Dog greets someone we want to our application to log that information.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7hrp8huy1js4jz9z8n2a.png)

In this case, our object is going to issue commands to other objects, so we need a mock or spy. First, we are going to state that `Dog` will be constructed with a `Logger`:

```php
<?php

# spec/App

class DogSpec extends ObjectBehavior
{
    function let(Logger $logger)
    {
        $this->beConstructedWith($logger);
    }
}
```

Now we can describe the interaction with a `Logger`:

```php
<?php

# spec/App

class DogSpec extends ObjectBehavior
{
     /// ...
    function it_logs_the_greeting(Named $named, Logger $logger)
    {
        $named->name()->willReturn('Marry');
        $logger->log('Hello Marry, Vuf Vuf')->shouldBeCalled();
        $this->greet($named);
    }
}
```

We are setting an expectation that the log method will be called with `Hello Mike, Vuf Vuf` once we execute our code. This is a **mock**. If we wish to use a **spy** we would describe it as:

```php
<?php

# spec/App

class DogSpec extends ObjectBehavior
{
     /// ...
    function it_logs_the_greeting(Named $named, Logger $logger)
    {
        $named->name()->willReturn('Mike');
        $this->greet($named);
        $logger->log('Hello Mike, Vuf Vuf')->shouldHaveBeCalled();
    }
}
```

As always, PHPSpec will help us by creating some methods or us:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/p1w1wc3cv7jxj7etsulr.png)

Then it's up to us to add some code to satisfy the spec:

```php
<?php

# src/App

class Dog
{

    // ...

    public function greet(Named $named)
    {
        $greeting = 'Hello ' . $named->name() . ', Vuf Vuf';
        $this->logger->log($greeting);
        return $greeting;
    }
}
```

* * *

<span>As you see, in PHPSpec we </span>**<span>describe</span>**<span> our object behaviors using a very descriptive syntax. There is always one spec per object/class which is why PHPSpec can only be used for testing at the unit layer/level. If you want to have some higher-level test you'll need to use some other tool. Maybe another BDD tool as </span>[<span>Behat</span>](https://docs.behat.org/en/latest/)<span> (don't get me started on how cool Behat is)? Another thing you probably don't want to do is introduce PHPSpec in a legacy codebase (with bad design). It will be painful and authors of PHPSpec never intended it to be used that way. But if you are starting a greenfield project, why not give PHPSpec a try. Hope you'll find is as fun as I do.</span>