+ All Categories
Home > Documents > Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View,...

Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View,...

Date post: 22-Aug-2020
Category:
Upload: others
View: 1 times
Download: 0 times
Share this document with a friend
38
Why, What, and How: Testing in 2014 Sebastian Bergmann | June 3 rd 2014
Transcript
Page 1: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

Why, What, and How: Testing in 2014Sebastian Bergmann | June 3rd 2014

Page 2: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

Sebastian BergmannDriven by his passion to help developers build better software.

Page 3: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

sharing experience

Page 4: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

Web Application» Presentation

(Presentation Model, View, Template)

» Application Logic(HTTP Abstraction, Routing, Controller)

» Domain Logic

» Persistence

Page 5: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain
Page 6: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

<?phpuseuse Behat\Mink\Session;useuse Behat\Mink\Driver\GoutteDriver;

abstract classabstract class MinkTestCase extendsextends PHPUnit_Framework_TestCase{

privateprivate $session$session;

protected functionprotected function setUp(){

$this$this->session = newnew Session(newnew GoutteDriver);}

protected functionprotected function visit($url$url){

$this$this->session->visit($url$url);

returnreturn $this$this->session->getPage();}

}

Page 7: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

<?phpclassclass ApplicationTest extendsextends MinkTestCase{

public functionpublic function testExamplePageContainsExampleText(){

$page$page = $this$this->visit('http://example.com/');

$this$this->assertContains('Example Domain',$page$page->getContent()

);}

}

Page 8: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

$ phpunit ApplicationTestPHPUnit 4.1.1 by Sebastian Bergmann.

.

Time: 1.52 seconds, Memory: 6.75Mb

OK (1 test, 1 assertion)

Page 9: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

$ phpunit --testdox ApplicationTestPHPUnit 4.1.1 by Sebastian Bergmann.

Application[x] Example page contains example text

Page 10: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

# features/example.featureFeature: Example...

Scenario: Accessing an example web page worksGiven I am on "/"Then I should see "Example Domain"

Page 11: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

$ behat features/example.featureFeature: Example...

Scenario: Accessing an example web page worksGiven I am on "/"Then I should see "Example Domain"

1 scenario (1 passed)2 steps (2 passed)0m1.789s

Page 12: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain
Page 13: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain
Page 14: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

"[T]he Rails community has adopted the strategy of writing hoards of

cucumber tests that drive the application through the web server. This leads

to slow and fragile tests and breaks many of the rules of TDD which tries to

keep tests from coupling to unnecessary system components like the GUI."

— Robert C. Martin

Page 15: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain
Page 16: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

<?phpnamespacenamespace Company\Project;

classclass Application{

public functionpublic function run(RequestInterface $request$request, ResponseInterface $response$response){

// ...}

}

Page 17: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

<?phpnamespacenamespace Company\Project;

interfaceinterface ResponseInterface{

public functionpublic function setData($key$key, $value$value);public functionpublic function getData($key$key);public functionpublic function hasData($key$key);

// ...}

Page 18: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

<?phpnamespacenamespace Company\Project\Tests;useuse Company\Project\Application;useuse Company\Project\Request;useuse Company\Project\Response;useuse PHPUnit_Framework_TestCase;

classclass HomepageTest extendsextends PHPUnit_Framework_TestCase{

protected functionprotected function setUp(){

$this$this->application = newnew Application;$this$this->request = newnew Request;$this$this->response = newnew Response;

}

public functionpublic function testHasNavigation(){

$this$this->application->run($this$this->request, $this$this->response);

$this$this->assertTrue($this$this->response->hasData('navigation'));}

}

Page 19: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

<?phpnamespacenamespace Company\Project\Tests;useuse Company\Project\Application;useuse Company\Project\Request;useuse Company\Project\Response;

classclass HomepageTest extendsextends IntegrationTestCase{

protected functionprotected function setUp(){

$this$this->application = newnew Application;$this$this->request = newnew Request;$this$this->response = newnew Response;

}

public functionpublic function testHasNavigation(){

$this$this->application->run($this$this->request, $this$this->response);

$this$this->assertResponseHasData('navigation', $this$this->response);}

}

Page 20: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

<?phpnamespacenamespace Company\Project\Tests;useuse Company\Project\ResponseInterface;useuse PHPUnit_Framework_TestCase;

abstract classabstract class IntegrationTestCase extendsextends PHPUnit_Framework_TestCase{

public functionpublic function assertResponseHasData($name$name, ResponseInterface $response$response){

$constraint$constraint = newnew DataExistsConstraint($response$response);$this$this->assertThat($name$name, $constraint$constraint);

}

public functionpublic function assertResponseNotHasData($name$name, ResponseInterface $response$response){

$constraint$constraint = newnew DataExistsConstraint($response$response);$this$this->assertThat($name$name, $this$this->logicalNot($constraint$constraint));

}}

Page 21: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

<?phpnamespacenamespace Company\Project\Tests;useuse Company\Project\ResponseInterface;useuse PHPUnit_Framework_Constraint;

classclass DataExistsConstraint extendsextends PHPUnit_Framework_Constraint{

privateprivate $response$response;

public functionpublic function __construct(ResponseInterface $response$response){

$this$this->response = $response$response;}

protected functionprotected function matches($other$other){

returnreturn $this$this->response->hasData($other$other);}

public functionpublic function toString(){

returnreturn 'data exists';}

}

Page 22: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain
Page 23: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

<?phpnamespacenamespace Company\Project;

classclass SampleWorkflow{

privateprivate $backend$backend;privateprivate $service$service;

public functionpublic function __construct(Backend $backend$backend, Service $service$service){

$this$this->backend = $backend$backend;$this$this->service = $service$service;

}

public functionpublic function execute(Request $request$request){

$this$this->service->doWork($this$this->backend->getObjectById($request$request->getValue('id'))

);}

}

Page 24: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

<?phpnamespacenamespace Company\Project;useuse PHPUnit_Framework_TestCase;

classclass SampleWorkflowTest extendsextends PHPUnit_Framework_TestCase{

public functionpublic function testServiceCallUpdatesObject(){

$service$service = $this$this->getMockBuilder('Service')->enableProxyingToOriginalMethods()->getMock();

$service$service->expects($this$this->once())->method('doWork');

$backend$backend = newnew Backend;$workflow$workflow = newnew SampleWorkflow($backend$backend, $service$service);

$workflow$workflow->execute(newnew Request(arrayarray('id' => 2204)));}

}

Page 25: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain
Page 26: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain
Page 27: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

Domain Logic"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

Page 28: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

Domain LogicWhen you cannot test your domain logic, the heart of your software, using

unit tests and in isolation from persistence and the web context ...

Page 29: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain
Page 30: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

TDD is dead. Long live testing."I rarely unit test in the traditional sense of the word, where all

dependencies are mocked out, and thousands of tests can close in seconds.

It just hasn't been a useful way of dealing with the testing of Rails

applications. I test active record models directly, letting them hit the

database, and through the use of fixtures. Then layered on top is currently a

set of controller tests, but I'd much rather replace those with even higher

level system tests through Capybara or similar."

— David Heinemeier Hansson

Page 31: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

Monogamous TDD"If you trust those integration tests so much that you are willing to deploy

when they pass; and if they execute so quickly that you can continuously

and effectively refactor and clean the code, then you aren't doing any better

than me. Do it."

— Robert C. Martin

Page 32: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

Monogamous TDD"But (and this is a big "but"), it seems to me that integration tests have very

little chance of meeting my two predicates."

— Robert C. Martin

Page 33: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain
Page 34: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

Effective Testing

— Rich Martin

» A high-fidelity test is one which is very sensitive to defects in the codeunder test

» A resilient test is one that only fails when a breaking change is made to thecode under test

» A high-precision test tells you exactly where the defect lies

Page 35: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

External and Internal Quality"Running end-to-end tests tells us about the the external quality of our

system, and writing them tells us something about how well we [...]

understand the domain, but end-to-end tests don't tell us how well we've

written the code. Writing unit tests gives us a lot of feedback about the

quality of our code, and running them tell us that we haven't broken any

classes [...]"

— Steve Freeman and Nat Pryce

Page 36: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain
Page 38: Why, What, and How: Testing in 2014 · Web Application » Presentation (Presentation Model, View, Template) » Application Logic (HTTP Abstraction, Routing, Controller) » Domain

sharing experience


Recommended