An open API service indexing awesome lists of open source software.

https://github.com/dimsav/phpspec-reference

A guide containing phpspec use cases
https://github.com/dimsav/phpspec-reference

Last synced: about 1 year ago
JSON representation

A guide containing phpspec use cases

Awesome Lists containing this project

README

          

PHPSpec reference guide
=======================

A guide containing phpspec snippets for different use cases

* [Commands](#commands)
* [Mocks](#mocks)
* [Exceptions](#exceptions)
* [Matching types](#matching-types)
* [Dynamic matching types](#dynamic-matching-types)
* [Plugins](#plugins)
* [Templates](#templates)
* [Tips](#tips)

## Installation

Install with composer using this composer command:

```
composer require phpspec/phpspec:2.*@dev --dev
```

Or by adding the depencency manually to your composer.json file:

```json
{
"require-dev": {
"phpspec/phpspec": "2.0.*@dev"
}
}
```

Optionally, add the following aliases to your system:

```bash
# PHPSpec Command

alias phpspec='vendor/bin/phpspec'

# PHPSpec Shortcuts

alias spec='vendor/bin/phpspec'
alias specr='vendor/bin/phpspec run'
alias specd='vendor/bin/phpspec describe'
```

## Commands

### Describe

`phpspec describe Namespaced/Class/Name`

Describe creates the spec file for the class you want to specify.

### Run

`phpspec run`

Run executes the specs and ends with a nice output.

![PhpSpec output](https://i.cloudup.com/EIw8gDuYrr-2000x2000.png)

## Mocks

### Creating mocks

#### Injecting mocks in constructor

Inject a mock in the constructor for use in your specs:

```php
// spec/Acme/HandlerSpec.php

function let(Acme\Dependency $dependency)
{
$this->beConstructedWith($dependency);
}

// Alternative syntax
function let($dependency)
{
$dependency->beADoubleOf('Acme\Dependency');
$this->beConstructedWith($dependency);
}
```

Pass in the spec the same mock variable name:

```php
// Our spec
function it_sends_the_message($dependency)
{
// $dependency is now the mock we created in let()
}
```

#### Injecting mocks in spec

```php
function it_sends_the_message(Acme\Dependency $dependency)
{
// $dependency is now a new mock of Acme\Dependency
}
```

### Using mocks

#### Returning values from mock methods

Imagine you have a Messenger class, containing a `send(Message $message)` method. While we run `send($message)` we want to make sure $message will return 'abc' when executed.

```php
function it_sends_the_message(Acme\Message $message)
{
$message->getContents()->willReturn('abc');
$this->send($message);
}
```

Now imagine you need to call a method several times and have a diferent value each time.

```php
function it_gets_three_random_numbers(Acme\RandomGenerator $rand)
{
$rand->generate()->willReturn(123, 432, 874);
$this->getNumbers($rand, 3)->shouldReturn([123, 432, 874]);
}
```

#### Specify that a mock method should be called

Usually we want to make sure that a mock method is executed. We do that with `shouldBeCalled()`.

```php
function it_sends_the_message(Acme\Message $message)
{
$message->getContents()->shouldBeCalled()->willReturn('abc');
$this->send($message);
}
```

## Exceptions

### Throw exception

Expect an `InvalidArgumentException` to be thrown when we call "send('bad')". Passing the exception type as string prevents the message validation.

```php
function it_throws_exception_during_send(Acme\Message $message)
{
$this->shouldThrow('\InvalidArgumentException')->duringSend('bad');
}
```

### Throw exception with message

Expect an `InvalidArgumentException` with message "Wrong argument" to be thrown when we call `send('bad')`:

```php
function it_throws_exception_during_send(Acme\Message $message)
{
$exception = new InvalidArgumentException('Wrong argument');

$this->shouldThrow($exception)->duringSend('bad');
}
```

### Throw exception in constructor

Expect an `InvalidArgumentException` to be thrown when we call the constructor `__construct('bad1, 'bad2')`. The exception is passed as instance without message. Therefore we expect no message when the exeption is thrown.

```php
function it_throws_exception_during_constructor(Acme\Message $message)
{
$this->shouldThrow(new \InvalidArgumentException)->during('__construct', array('bad1', 'bad2'));
}
```

## Matching types

### Identical

```php
$this->method()->shouldBe($result);

// Alternative syntax
$this->method()->shouldReturn($result);
$this->method()->shouldEqual($result);
$this->method()->shouldBeEqualTo($result);
```

### Equal

```php
$this->method()->shouldBeLike($result)
```

### Data types

Expect the result of a method has a specific data type.

```php
$this->method()->shouldBeBool();
$this->method()->shouldBeObject();
$this->method()->shouldBeString();
$this->method()->shouldBeInteger();
$this->method()->shouldBeDecimal();
$this->method()->shouldBeArray();
```

### Objects

All the following syntaxes expect that method() returns an instance of the given class.

```php
$this->method()->shouldHaveType('\Full\Class\Name');
$this->method()->shouldReturnAnInstanceOf('\Full\Class\Name');
$this->method()->shouldBeAnInstanceOf('\Full\Class\Name');
$this->method()->shouldImplement('\Full\Class\Name');
```

### Count

You can use `shouldHaveCount()` on a method returning an `array` or an instance of `\Countable`.

```php
$this->getArray()->shouldHaveCount(2)
$this->getCollection()->shouldHaveCount(2)
```

```php
public function getArray() {
return array(1, 2)
}

public function getCollection() {
return $this->users;
}
```

You can also use `shouldHaveCount()` on `$this`, if it is an instance of `\Countable`.

```php

$this->shouldHaveCount(10);

class UsersCollection implements \Countable {

public function count() {
return count($this->users);
}
}
```

## Dynamic matching types

### Boolean shouldBe*

To use the shouldBe* matching, the class should have a public method starting with "is".

```php
// User.php
public function isActive() {
return (bool) $this->isActive;
}
```

```php
// expect isActive returns true
$this->shouldBeActive();

// expect isActive returns false
$this->shouldNotBeActive();
```

### Boolean shouldHave*

To use the shouldHave* matching, the class should have a public method starting with "has".

```php
// User.php
public function hasProfile() {
return (bool) $this->hasProfile;
}
```

```php
// expect hasProfile returns true
$this->shouldHaveProfile();

// expect hasProfile returns false
$this->shouldNotHaveProfile();
```

### Custom types

Custom types give us the possibility to expect something using a closure. To do that we have to define a "getMatchers()" method in our spec class.

#### getMatchers()

getMatchers() should return an array with keys describing the expectations and values the closures containing the logic of the expectations. The first parameter in the closure is the output of the executed method.

```php

function getMatchers()
{
return array(
'haveLength' => function($result, $count) {
return strlen($result) == $count;
}
);
}
```

#### Using getMatchers()

To use the above expectation we use the method `should` + `{getMatchers key}`.

```php
$this->method()->shouldHaveLength(12);
```

## Plugins

* [Code coverage](https://github.com/dimsav/phpspec-reference/wiki/PhpSpec:-Code-coverage-plugin)

## Templates

Custom templates can be used when phpspec generates php code. There are three template types, each of which, requires a different file name:

* Specs: [specification.tpl](#specification-template)
* Classes: [class.tpl](#class-template)
* Methods: [method.tpl](#method-template)

Phpspec will look for template files in these locations with the following order:

1. `{project_directory}/.phpspec/`
2. `{user_home_directory}/.phpspec/`

To see the available template parameters visit the [parameters chapter](http://www.phpspec.net/cookbook/templates.html#parameters) in the docs.

#### Specification template

```
Required parameter $ missing

To fix that, I edit the docblock of the ObjectBehavior.php file in the vendor directory.

```php
/*
* @method void beConstructedWith($constructorArguments,...)
*/

// change to

/*
* @method void beConstructedWith($constructorArguments)
*/
```

### Expected ... (?)

When we expect some string to be returned, we need more details about the differences of the output and the expected string.

> expected "some long string that is ...", but got "some different long strin...".

This message isn't very helpful. To get the full difference in the string, plus lots of other information, pass the `-v` option:

`phpspec run -v`

will now output something like

```
25 ✘ should match strings
expected "some long string that is ...", but got "some different long strin...".

@@ -1,1 +1,1 @@
-some long string that is really long.
+some different long string that is really long.

25 function it_should_match_strings()
26 {
27 $this->foo()->shouldReturn('some long string that is really long.');
28 }
29

0 vendor/phpspec/phpspec/src/PhpSpec/Matcher/IdentityMatcher.php:78
throw new PhpSpec\Exception\Example\NotEqualException("Expected "some lon...")
1 [internal]
Spec\Foo\StringSpec->it_should_match()
```

This also works with objects:

```
@@ -1,4 +1,4 @@
-stdClass Object &000000000f3eb7a000000000285a17d7 (
- 'foo' => 'bar'
+stdClass Object &000000000f3eb78e00000000285a17d7 (
+ 'bax' => 'bar'
'bar' => 'foo'
)
```

and arrays:

```
@@ -1,4 +1,4 @@
[
far => ""foo"...",
- boo => ""baz"...",
+ boo => ""bar"...",
]
```

## Sources

* https://github.com/phpspec/phpspec-docs/blob/master/en/writing-specs.rst
* http://www.slideshare.net/marcello.duarte/phpspec-bdd-for-php
* https://github.com/yvoyer/phpspec-cheat-sheet