Testing on the Edge Sebastian Bergmann October 28th 2013
Sebastian Bergmann» Has instrumentally contributed to transforming PHP into a reliable platform for large-scale, critical projects.» Enterprises and PHP developers around the world benefit from the tools that he has developed and the experience he shares. sharing experience
sharing experience
Presentation Model Presentation View Template HTTP Abstraction Application Logic Routing Controller Domain Logic Persistence
Responsible for representing concepts of the business, information about the business situation, and business rules. State that reflects the business situation is controlled and used here, even though the technical details of storing it are delegated to the infrastructure. This layer is the heart of business software. Eric Evans Domain Logic
Unit
Unit Stub / Mock
Unit Unit
Disintegration Testing The peer review preliminary findings indicate that one team used English units (e.g., inches, feet and pounds) while the other used metric units for a key spacecraft operation. http://mars.jpl.nasa.gov/msp98/news/mco990930.html
Client Server
Selenium
Behat + Mink
PHPUnit + Mink
<?php use Behat\Mink\Session; use Behat\Mink\Driver\GoutteDriver; abstract class MinkTestCase extends PHPUnit_Framework_TestCase private $session; protected function setup() $this->session = new Session(new GoutteDriver); protected function visit($url) $this->session->visit($url); return $this->session->getpage(); sharing experience
<?php class ApplicationTest extends MinkTestCase public function testexamplepagecontainsexampletext() $page = $this->visit('http://example.com/'); $this->assertcontains( 'Example Domain', $page->getcontent() ); sharing experience
Client Server
<?php namespace Company\Project; class Application public function run(requestinterface $request, ResponseInterface $response) //... sharing experience
<?php namespace Company\Project; interface ResponseInterface public function setdata($key, $value); public function getdata($key); public function hasdata($key); //... sharing experience
<?php namespace Company\Project\Tests; use Company\Project\Application; use Company\Project\Request; use Company\Project\Response; class HomepageTest extends PHPUnit_Framework_TestCase protected function setup() $this->application = new Application; $this->request = new Request; $this->response = new Response; public function testhasnavigation() $this->application->run($this->request, $this->response); $this->asserttrue($this->response->hasdata('navigation')); sharing experience
<?php namespace Company\Project\Tests; use Company\Project\Application; use Company\Project\Request; use Company\Project\Response; class HomepageTest extends PHPUnit_Framework_TestCase protected function setup() $this->application = new Application; $this->request = new Request; $this->response = new Response; public function testhasnavigation() $this->application->run($this->request, $this->response); $this->asserttrue($this->response->hasdata('navigation')); sharing experience
<?php namespace Company\Project\Tests; use Company\Project\Application; use Company\Project\Request; use Company\Project\Response; class HomepageTest extends IntegrationTestCase protected function setup() $this->application = new Application; $this->request = new Request; $this->response = new Response; public function testhasnavigation() $this->application->run($this->request, $this->response); $this->assertresponsehasdata('navigation', $this->response); sharing experience
Implementing Custom Assertions
<?php namespace Company\Project\Tests; use Company\Project\ResponseInterface; use PHPUnit_Framework_TestCase; abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase sharing experience
<?php namespace Company\Project\Tests; use Company\Project\ResponseInterface; use PHPUnit_Framework_TestCase; abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase public function assertresponsehasdata($name, ResponseInterface $response) sharing experience
<?php namespace Company\Project\Tests; use Company\Project\ResponseInterface; use PHPUnit_Framework_TestCase; abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase public function assertresponsehasdata($name, ResponseInterface $response) $constraint = new DataExistsConstraint($response); sharing experience
<?php namespace Company\Project\Tests; use Company\Project\ResponseInterface; use PHPUnit_Framework_Constraint; class DataExistsConstraint extends PHPUnit_Framework_Constraint private $response; public function construct(responseinterface $response) $this->response = $response; protected function matches($other) return $this->response->hasdata($other); public function tostring() return 'data exists'; sharing experience
<?php namespace Company\Project\Tests; use Company\Project\ResponseInterface; use PHPUnit_Framework_TestCase; abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase public function assertresponsehasdata($name, ResponseInterface $response) $constraint = new DataExistsConstraint($response); $this->assertthat($name, $constraint); sharing experience
<?php namespace Company\Project\Tests; use Company\Project\ResponseInterface; use PHPUnit_Framework_TestCase; abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase public function assertresponsehasdata($name, ResponseInterface $response) $constraint = new DataExistsConstraint($response); $this->assertthat($name, $constraint); public function assertresponsenothasdata($name, ResponseInterface $response) $constraint = new DataExistsConstraint($response); $this->assertthat($name, $this->logicalnot($constraint)); sharing experience
Looking ahead: Test Proxies in PHPUnit 3.8
<?php namespace Company\Project; class SampleWorkflow private $backend; private $service; public function construct(backend $backend, Service $service) $this->backend = $backend; $this->service = $service; public function execute(request $request) $this->service->dowork( $this->backend->getobjectbyid($request->getvalue('id')) ); sharing experience
<?php namespace Company\Project; use PHPUnit_Framework_TestCase; class SampleWorkflowTest extends PHPUnit_Framework_TestCase public function testservicecallupdatesobject() $service = $this->getmockbuilder('service') ->enableproxyingtooriginalmethods() ->getmock(); $service->expects($this->once()) ->method('dowork'); $backend = new Backend; $workflow = new SampleWorkflow($backend, $service); $workflow->execute(new Request(array('id' => 2204))); sharing experience
talks.thephp.cc sebastian@thephp.cc @s_bergmann
Become a Certified PHP Craftsman in 2014! http://thephpcurriculum.com/