Last active
September 26, 2018 23:22
-
-
Save jakzal/23da90ee018c5f5c1927a67088a4c631 to your computer and use it in GitHub Desktop.
Test double examples
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php declare(strict_types=1); | |
namespace App\Tests\Doubles; | |
use PHPUnit\Framework\TestCase; | |
class Item | |
{ | |
} | |
interface Basket | |
{ | |
/** | |
* @return Item[] | |
*/ | |
public function items(): array; | |
public function add(Item $item): void; | |
} | |
class Foo | |
{ | |
private $basket; | |
public function __construct(Basket $basket) | |
{ | |
$this->basket = $basket; | |
} | |
public function a(): bool | |
{ | |
return true; | |
} | |
public function b(): array | |
{ | |
return $this->basket->items(); | |
} | |
public function c(Item $item): void | |
{ | |
$this->basket->add($item); | |
} | |
} | |
class DoublesTest extends TestCase | |
{ | |
public function test_custom_dummy() | |
{ | |
$basketDummy = new class implements Basket { | |
public function items(): array | |
{ | |
} | |
public function add(Item $item): void | |
{ | |
} | |
}; | |
$foo = new Foo($basketDummy); | |
$this->assertTrue($foo->a()); | |
} | |
public function test_prophecy_dummy() | |
{ | |
$basketDummy = $this->prophesize(Basket::class); | |
$foo = new Foo($basketDummy->reveal()); | |
$this->assertTrue($foo->a()); | |
} | |
public function test_phpunit_dummy() | |
{ | |
$basketDummy = $this->createMock(Basket::class); | |
$foo = new Foo($basketDummy); | |
$this->assertTrue($foo->a()); | |
} | |
public function test_custom_stub() | |
{ | |
$items = [new Item(), new Item()]; | |
$basketStub = new class($items) implements Basket { | |
private $items; | |
public function __construct(array $items) | |
{ | |
$this->items = $items; | |
} | |
public function items(): array | |
{ | |
return $this->items; | |
} | |
public function add(Item $item): void | |
{ | |
} | |
}; | |
$foo = new Foo($basketStub); | |
$this->assertSame($items, $foo->b()); | |
} | |
public function test_prophecy_stub() | |
{ | |
$items = [new Item(), new Item()]; | |
$basketStub = $this->prophesize(Basket::class); | |
$basketStub->items()->willReturn($items); | |
$foo = new Foo($basketStub->reveal()); | |
$this->assertSame($items, $foo->b()); | |
} | |
public function test_phpunit_stub() | |
{ | |
$items = [new Item(), new Item()]; | |
$basketStub = $this->createMock(Basket::class); | |
$basketStub->expects($this->any()) | |
->method('items') | |
->willReturn($items); | |
$foo = new Foo($basketStub); | |
$this->assertSame($items, $foo->b()); | |
} | |
public function test_custom_mock_object() | |
{ | |
$item = new Item(); | |
$basketMock = new class implements Basket { | |
public $addedItem; | |
public function items(): array | |
{ | |
} | |
public function add(Item $item): void | |
{ | |
$this->addedItem = $item; | |
} | |
public function __destruct() | |
{ | |
if (null === $this->addedItem) { | |
throw new \LogicException('Expected "add" method to be called.'); | |
} | |
} | |
}; | |
$foo = new Foo($basketMock); | |
$foo->c($item); | |
} | |
public function test_prophecy_mock_object() | |
{ | |
$item = new Item(); | |
$basketMock = $this->prophesize(Basket::class); | |
$basketMock->add($item)->shouldBeCalled(); | |
$foo = new Foo($basketMock->reveal()); | |
$foo->c($item); | |
} | |
public function test_phpunit_mock_object() | |
{ | |
$item = new Item(); | |
$basketMock = $this->createMock(Basket::class); | |
$basketMock->expects($this->once()) | |
->method('add') | |
->with($item); | |
$foo = new Foo($basketMock); | |
$foo->c($item); | |
} | |
public function test_custom_spy() | |
{ | |
$item = new Item(); | |
$basketSpy = new class implements Basket { | |
public $addedItem; | |
public function items(): array | |
{ | |
} | |
public function add(Item $item): void | |
{ | |
$this->addedItem = $item; | |
} | |
}; | |
$foo = new Foo($basketSpy); | |
$foo->c($item); | |
$this->assertSame($item, $basketSpy->addedItem); | |
} | |
public function test_prophecy_spy() | |
{ | |
$item = new Item(); | |
$basketSpy = $this->prophesize(Basket::class); | |
$foo = new Foo($basketSpy->reveal()); | |
$foo->c($item); | |
$basketSpy->add($item)->shouldHaveBeenCalled(); | |
} | |
public function test_phpunit_spy() | |
{ | |
// there is a way, but it’s ugly. Google “spying with phpunit" | |
} | |
public function test_fake_object() | |
{ | |
$item = new Item(); | |
$basketFake = new class implements Basket { | |
private $items = []; | |
public function items(): array | |
{ | |
return $this->items; | |
} | |
public function add(Item $item): void | |
{ | |
$this->items[] = $item; | |
} | |
}; | |
$foo = new Foo($basketFake); | |
$foo->c($item); | |
$this->assertSame([$item], $foo->b()); | |
} | |
public function test_prophecy_fake_object() | |
{ | |
$item = new Item(); | |
$basketFake = $this->prophesize(Basket::class); | |
$basketFake->add($item)->will(function ($args) { | |
$this->items()->willReturn([$args[0]]); | |
}); | |
$foo = new Foo($basketFake->reveal()); | |
$foo->c($item); | |
$this->assertSame([$item], $foo->b()); | |
} | |
public function test_phpunit_fake_object() | |
{ | |
$item = new Item(); | |
$basketFake = $this->createMock(Basket::class); | |
$basketFake->method('add') | |
->with($item) | |
->will($this->returnCallback(function (Item $item) use ($basketFake) { | |
$basketFake->method('items')->willReturn([$item]); | |
})); | |
$foo = new Foo($basketFake); | |
$foo->c($item); | |
$this->assertSame([$item], $foo->b()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment