to
By Vaidas Mikalauskas
TDD
Test-driven development (TDD) is a development technique where you must first write a test that fails before you write new functional code
BDD
Behaviour-driven development is largely facilitated through the use of a simple domain-specific language (DSL) using natural language constructs (e.g., English-like sentences) that can express the behavior and the expected outcomes
TDD vs BDD
PHPUnit
BEHAT
Feature: ls
In order to see the directory structure
As a UNIX user
I need to be able to list the contents
Scenario: List 2 files in a directory
Given I am in a directory "test"
And I have a file named "foo"
And I have a file named "bar"
When I run "ls"
Then I should get:
"""
bar
foo
"""<?php
class Ls {
function show($dir) {
return array_splice(scandir($dir), 2);
}
}
class LsTest extends PHPUnit_Framework_TestCase {
function setUp() {
!is_dir('/tmp/files') && mkdir('/tmp/files');
}
function testCurrentDirectoryLists2Files() {
$ls = new Ls();
touch('/tmp/files/foo');
touch('/tmp/files/bar');
$files = $ls->show('/tmp/files');
$this->assertEquals(['bar', 'foo'], $files);
}
}Leave it for the next time
Installation
{
"autoload": {
"psr-4": {
"App\\": "src"
}
},
"require-dev": {
"phpunit/phpunit": "^5.0"
}
}phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true">
<testsuites>
<testsuite name="Application Test Suite">
<directory>./tests</directory>
</testsuite>
</testsuites>
</phpunit>./src/Foo.php
./src/Bar.php
./src/Controller/Baz.php./tests/FooTest.php
./tests/BarTest.php
./tests/Controller/BazTest.php<?php namespace Tests;
class FooTest extends \PHPUnit_Framework_TestCase {
function test...() {
...
}
}<?php namespace Tests\App;
use App\TestableFoo;
class TestableFooTest extends \PHPUnit_Framework_TestCase {
/**
* @var TestableFoo
*/
private $object;
function setUp() {
$this->object = new TestableFoo();
}
function testIsInitializable() {
$this->assertInstanceOf(
TestableFoo::class, $this->object
);
}
function testGetTrueIsTrue() {
$this->assertTrue(
$this->object->getTrue()
);
}
}<?php namespace App;
class TestableFoo {
public function getTrue() {
return true;
}
}The main assertations are:
The list is:
https://phpunit.de/manual/current/en/appendixes.assertions.html
Mocking is creating objects that
simulate the behaviour of real objects
There are a few libraries for php:
Mocking is creating objects that
simulate the behaviour of real objects
There are a few libraries for php:
<?php namespace App;
class Payment {
public $from;
public $to;
public $amount;
public function __construct(
$from, $to, $amount
) {
$this->from = $from;
$this->to = $to;
$this->amount = $amount;
}
}
class PaymentManager {
const $url = "https://do.more.com/payment";
public function __construct(\GuzzleHttp\Client $client) {
$this->client = $client;
}
public function makePayment(Payment $payment) {
$response = $this->sendRequest($payment);
return $response->getStatusCode() == 200;
}
private function sendRequest(Payment $payment) {
return $this->client->request("POST", self::URL, [
'form_params' => [
'to' => $payment->to,
'from' => $payment->from,
'amount' => $payment->amount,
]
]);
}
}<?php namespace Test\App;
use App\PaymentManager;
use App\Payment;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Response;
class PaymentManagerTest extends \PHPUnit_Framework_TestCase {
private $client;
private $object;
function setUp() {
$this->client = $this->getMockBuilder(Client::class)->getMock();
$this->object = new PaymentManager($this->client);
}
function testPaymentIsSuccessfull() {
$response = new Response();
$this->client->expects($this->once())->method('request')
->will($this->returnValue($response));
$payment = new Payment("to@datadog.org", "from@datadog.org", 10.00);
$result = $this->object->makePayment($payment);
$this->assertTrue($result);
}
}Common questions:
<?php namespace App;
class NaughtyConstructor {
public $html;
public function __construct($url) {
$this->html = file_get_contents($url);
}
public function getMetaTags() {
$mime = 'text/plain';
$filename = "data://{$mime};base64," . base64_encode($this->html);
return get_meta_tags($filename);
}
public function getTitle() {
preg_match("#<title>(.+)</title>#siU", $this->html, $matches);
return !empty($matches[1]) ? $matches[1] : false;
}
}
<?php namespace Test\App;
use App\NaughtyConstructor;
class NaughtyConstructorTest extends \PHPUnit_Framework_TestCase {
public function testGetMetaTagsReturnsArrayOfProperties() {
$naughty = $this->getMockBuilder(NaughtyConstructor::class)
->setMethods(array('__construct'))
->setConstructorArgs(array('http://data.dog'))
->disableOriginalConstructor()
->getMock();
$naughty->html = $this->getHtml();
$result = $naughty->getMetaTags();
$this->assertEquals('DATADOG', $result['author']);
}
protected function getHtml() {
return '<html lang="en">
<head>
<meta name="title" content="Welcome"/>
<meta name="author" content="DATADOG"/>
</head>
<body></body>
</html>';
}
}
Q&A