SlideShare una empresa de Scribd logo
1 de 64
Descargar para leer sin conexión
Building a Test
Pyramid: Symfony
testing strategies
with Ciaran McNulty
Before we start:
You must test your
applications!
What kind of tests to use?
» Manual testing
» Acceptance testing
» Unit testing
» Integration testing
» End-to-end testing
» Black box / white box
What tools to use?
» PHPUnit
» PhpSpec
» Behat
» Codeception
» BrowserKit / Webcrawler
Question:
Why can't someone
tell me which one to
use?
Answer:
Because there is no
best answer that fits
all cases
You have to find the
Testing different layers
Introducing the pyramid
» Defined by Mike Cohn in Succeeding with Agile
» For understanding different layers of testing
UI layer tests
» Test the whole application end-to-end
» Sensitive to UI changes
» Aligned with acceptance criteria
» Does not require good code
» Probably slow
e.g. Open a browser, fill in the form and submit it
Service layer tests
» Test the application logic by making service calls
» Faster than UI testing
» Aligned with acceptance criteria
» Mostly written in the target language
» Requires high-level services to exist
e.g. Instantiate the Calculator service and get it to add two
numbers
Unit level tests
» Test individual classes
» Much faster than service level testing
» Very fine level of detail
» Requires good design
Why a pyramid?
» Each layer builds on the one below it
» Lower layers are faster to run
» Higher levels are slower and more brittle
» Have more tests at the bottom than at the top
Why do you want
tests?
The answer will affect the type of
tests you write
If you want existing
features from
breaking
... write Regression Tests
Regression tests
» Check that behaviour hasn't changed
» Easiest to apply at the UI level
» ALL tests become regression tests eventually
'Legacy' code
class BasketController extends Controller
{
public function addAction(Request $request)
{
$productId = $request->attributes->get('product_id');
$basket = $request->getSession()->get('basket_context')->getCurrent();
$products = $basket->getProducts();
$products[] = $productId;
$basket->setProducts($products);
return $this->render('::basket.html.twig', ['basket' => $basket]);
}
}
Regression testing with PHPUnit
+ BrowserKit
class PostControllerTest extends WebTestCase
{
public function testShowPost()
{
$client = static::createClient();
$crawler = $client->request('GET', '/products/1234');
$form = $crawler->selectButton('Add to basket')->form();
$client->submit($form, ['id'=>1234]);
$product = $crawler->filter('html:contains("Product: 1234")');
$this->assertCount(1, $product);
}
}
Regression testing with
Codeception
$I = new AcceptanceTester($scenario);
$I->amOnPage('/products/1234');
$I->click('Add to basket');
$I->see('Product: 1234');
Regression testing with Behat +
MinkExtension
Scenario: Adding a product to the basket
Given I am on "/product/1234"
When I click "Add to Basket"
Then I should see "Product: 1234"
Regression testing with Ghost
Inspector
When regression testing
» Use a tool that gets you coverage quickly and easily
» Plan to phase out regression tests later
» Lean towards testing end-to-end
» Recognise they will be hard to maintain
If you want to match
customer
requirements better
... write Acceptance Tests
Acceptance Tests
» Check the system does what the customer wants
» Are aligned with customer language and intention
» Write them in English (or another language) first
» Can be tested at the UI or Service level
Start with an
example-led
conversation
... before you start working on it
... but not too long before
» "What should the system do when X happens?"
» "Does Y always happen when X?"
» "What assumptions Z are causing Y to be the outcome?"
» "Given Z when X then Y"
» "What other things aside from Y might happen?"
» "What if...?"
Write the examples
out in business-
readable tests
Try and make the code look like
the natural conversation you had
Easiest to test through
the User Interface
UI Acceptance testing with
PHPUnit + BrowserKit
class PostControllerTest extends WebTestCase
{
public function testAddingProductToTheBasket()
{
$this->addProductToBasket(1234);
$this->productShouldBeShownInBasket(1234);
}
private function addProductToBasket($productId)
{
//... browser automation code
}
private function productShouldBeShownInBasket($productId)
{
//... browser automation code
}
}
UI Acceptance testing with
Codeception
$I = new AcceptanceTester($scenario);
$I->amGoingTo('Add a product to the basket');
$I->amOnPage('/products/1234');
$I->click('Add to basket');
$I->expectTo('see the product in the basket');
$I->see('Product: 1234');
UI Acceptance testing with Behat
+ MinkExtension
Scenario: Adding a product to the basket
When I add product 1234 to the basket
Then I should see product 1234 in the basket
UI Acceptance testing with Behat
+ MinkExtension
/**
* @When I add product :productId to the basket
*/
public function iAddProduct($productId)
{
$this->visitUrl('/product/' . $productId);
$this->getSession()->clickButton('Add to Basket');
}
/**
* @Then I should see product :productId in the basket
*/
public function iShouldSeeProduct($productId)
{
$this->assertSession()->elementContains('css', '#basket', 'Product: ' . $productId);
}
Acceptance testing
through the UI is slow
and brittle
To test at the service layer, we
need to introduce services
'Legacy' code
class BasketController extends Controller
{
public function addAction(Request $request)
{
$productId = $request->attributes->get('product_id');
$basket = $request->getSession()->get('basket_context')->getCurrent();
$products = $basket->getProducts();
$products[] = $productId;
$basket->setProducts($products);
return $this->render('::basket.html.twig', ['basket' => $basket]);
}
}
'Service-oriented' code
class BasketController extends Controller
{
public function addAction(Request $request)
{
$basket = $this->get('basket_context')->getCurrent();
$productId = $request->attributes->get('product_id');
$basket->addProduct($productId);
return $this->render('::basket.html.twig', ['basket' => $basket]);
}
}
A very small change
but now the business logic is out of
the controller
Service layer Acceptance testing
with PHPUnit
class PostControllerTest extends PHPUnit_Framework_TestCase
{
public function testAddingProductToTheBasket()
{
$basket = new Basket(new BasketArrayStorage());
$basket->addProduct(1234);
$this->assertContains(1234, $basket->getProducts());
}
}
Service layer acceptance testing
with Behat + MinkExtension
Scenario: Adding a product to the basket
When I add product 1234 to the basket
Then I should see product 1234 in the basket
Service layer acceptance testing
with Behat
/**
* @When I add product :productId to the basket
*/
public function iAddProduct($productId)
{
$this->basket = new Basket(new BasketArrayStorage());
$this->basket->addProduct($productId);
}
/**
* @Then I should see product :productId in the basket
*/
public function iShouldSeeProduct($productId)
{
assert(in_array($productId, $this->basket->getProducts());
}
When all of the
acceptance tests are
running against the
Service layer
... how many also need to be run
through the UI?
Symfony is a controller for your
app
If you test everything
through services
... you only need
enough UI tests to be
sure the UI is
Multiple Behat suites
Scenario: Adding a product to the basket
When I add product 1234 to the basket
Then I should see product 1234 in the basket
Scenario: Adding a product that is already there
Given I have already added product 1234 to the basket
When I add product 1234 to the basket
Then I should see 2 instances of product 1234 in the basket
@ui
Scenario: Adding two products to my basket
Given I have already added product 4567 to the basket
When I add product 1234 to the basket
Then I should see product 4567 in the basket
And I should also see product 1234 in the basket
Multiple Behat suites
default:
suites:
ui:
contexts: [ UiContext ]
filters: { tags: @ui }
service:
contexts: [ ServiceContext ]
If you want the design
of your code to be
better
... write Unit Tests
Unit Tests
» Check that a class does what you expect
» Use a tool that makes it easy to test classes in isolation
» Move towards writing them first
» Unit tests force you to have good design
» Probably too small to reflect acceptance criteria
Unit tests are too granular
Customer: "The engine needs to produce 500bhp"
Engineer: "What should the diameter of the main drive shaft
be?"
Unit testing in PHPUnit
class BasketTest extends PHPUnit_Framework_Testcase
{
public function testGetsProductsFromStorage()
{
$storage = $this->getMock('BasketStorage');
$storage->expect($this->once())
->method('persistProducts')
->with([1234]);
$basket = new Basket($storage);
$basket->addProduct(1234);
}
}
Unit testing in PhpSpec
class BasketSpec extends ObjectBehavior
{
function it_gets_products_from_storage(BasketStorage $storage)
{
$this->beConstructedWith($storage);
$this->addProduct(1234);
$storage->persistProducts([1234])->shouldHaveBeenCalled([1234]);
}
}
Unit test
... code that is responsible for
business logic
... not code that interacts with
infrastructure including Symfony
You can unit test
interactions with
Symfony (e.g.
controllers)
You shouldn't need to if you have
acceptance tests
Coupled architecture
Unit testing third party
dependencies
class FileHandlerSpec extends ObjectBehaviour
{
public function it_uploads_data_to_the_cloud_when_valid(
CloudApi $client, FileValidator $validator, File $file
)
{
$this->beConstructedWith($client, $validator);
$validator->validate($file)->willReturn(true);
$client->startUpload()->shouldBeCalled();
$client->uploadData(Argument::any())->shouldBeCalled();
$client->uploadSuccessful()->willReturn(true);
$this->process($file)->shouldReturn(true);
}
}
Coupled architecture
Layered architecture
Testing layered architecture
class FileHandlerSpec extends ObjectBehaviour
{
public function it_uploads_data_to_the_cloud_when_valid(
FileStore $filestore, FileValidator $validator, File $file
)
{
$this->beConstructedWith($filestore, $validator);
$validator->validate($file)->willReturn(true);
$this->process($file);
$filestore->store($file)->shouldHaveBeenCalled();
}
}
Testing layered architecture
class CloudFilestoreTest extends PHPUnit_Framework_TestCase
{
function testItStoresFiles()
{
$testCredentials = …
$file = new File(…);
$apiClient = new CloudApi($testCredentials);
$filestore = new CloudFileStore($apiClient);
$filestore->store($file);
$this->assertTrue($apiClient->fileExists(…));
}
}
Testing layered architecture
To build your
pyramid...
Have isolated unit-
tested objects
representing your core
business logic
10,000s of tests running in <10ms
each
Have acceptance tests
at the service level
1,000s of tests running in <100ms
each
Have the bare
minimum of
acceptance tests at the
UI level
10s of tests running in <10s each
Thank You!
Any questions?
https://joind.in/talk/view/14972
@ciaranmcnulty
ciaran@sessiondigital.co.uk

Más contenido relacionado

La actualidad más candente

Event Sourcing & CQRS, Kafka, Rabbit MQ
Event Sourcing & CQRS, Kafka, Rabbit MQEvent Sourcing & CQRS, Kafka, Rabbit MQ
Event Sourcing & CQRS, Kafka, Rabbit MQAraf Karsh Hamid
 
React + Redux Introduction
React + Redux IntroductionReact + Redux Introduction
React + Redux IntroductionNikolaus Graf
 
Effective Spring Transaction Management
Effective Spring Transaction ManagementEffective Spring Transaction Management
Effective Spring Transaction ManagementUMA MAHESWARI
 
Clean architecture with ddd layering in php
Clean architecture with ddd layering in phpClean architecture with ddd layering in php
Clean architecture with ddd layering in phpLeonardo Proietti
 
Zero downtime deployment of micro-services with Kubernetes
Zero downtime deployment of micro-services with KubernetesZero downtime deployment of micro-services with Kubernetes
Zero downtime deployment of micro-services with KubernetesWojciech Barczyński
 
Docker Swarm 0.2.0
Docker Swarm 0.2.0Docker Swarm 0.2.0
Docker Swarm 0.2.0Docker, Inc.
 
Spring Framework Petclinic sample application
Spring Framework Petclinic sample applicationSpring Framework Petclinic sample application
Spring Framework Petclinic sample applicationAntoine Rey
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with SpringJoshua Long
 
Extending kubernetes with CustomResourceDefinitions
Extending kubernetes with CustomResourceDefinitionsExtending kubernetes with CustomResourceDefinitions
Extending kubernetes with CustomResourceDefinitionsStefan Schimanski
 
Java 8, Streams & Collectors, patterns, performances and parallelization
Java 8, Streams & Collectors, patterns, performances and parallelizationJava 8, Streams & Collectors, patterns, performances and parallelization
Java 8, Streams & Collectors, patterns, performances and parallelizationJosé Paumard
 
Introduction to Version Control
Introduction to Version ControlIntroduction to Version Control
Introduction to Version ControlJeremy Coates
 
Clean architecture
Clean architectureClean architecture
Clean architectureLieven Doclo
 

La actualidad más candente (20)

React Hooks
React HooksReact Hooks
React Hooks
 
DevOps with Kubernetes
DevOps with KubernetesDevOps with Kubernetes
DevOps with Kubernetes
 
Docker
DockerDocker
Docker
 
Docker, LinuX Container
Docker, LinuX ContainerDocker, LinuX Container
Docker, LinuX Container
 
Event Sourcing & CQRS, Kafka, Rabbit MQ
Event Sourcing & CQRS, Kafka, Rabbit MQEvent Sourcing & CQRS, Kafka, Rabbit MQ
Event Sourcing & CQRS, Kafka, Rabbit MQ
 
React + Redux Introduction
React + Redux IntroductionReact + Redux Introduction
React + Redux Introduction
 
Effective Spring Transaction Management
Effective Spring Transaction ManagementEffective Spring Transaction Management
Effective Spring Transaction Management
 
react redux.pdf
react redux.pdfreact redux.pdf
react redux.pdf
 
Kubernetes
KubernetesKubernetes
Kubernetes
 
Clean architecture with ddd layering in php
Clean architecture with ddd layering in phpClean architecture with ddd layering in php
Clean architecture with ddd layering in php
 
Zero downtime deployment of micro-services with Kubernetes
Zero downtime deployment of micro-services with KubernetesZero downtime deployment of micro-services with Kubernetes
Zero downtime deployment of micro-services with Kubernetes
 
Docker Swarm 0.2.0
Docker Swarm 0.2.0Docker Swarm 0.2.0
Docker Swarm 0.2.0
 
Spring Framework Petclinic sample application
Spring Framework Petclinic sample applicationSpring Framework Petclinic sample application
Spring Framework Petclinic sample application
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with Spring
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
 
Extending kubernetes with CustomResourceDefinitions
Extending kubernetes with CustomResourceDefinitionsExtending kubernetes with CustomResourceDefinitions
Extending kubernetes with CustomResourceDefinitions
 
Java 8, Streams & Collectors, patterns, performances and parallelization
Java 8, Streams & Collectors, patterns, performances and parallelizationJava 8, Streams & Collectors, patterns, performances and parallelization
Java 8, Streams & Collectors, patterns, performances and parallelization
 
CKA_1st.pptx
CKA_1st.pptxCKA_1st.pptx
CKA_1st.pptx
 
Introduction to Version Control
Introduction to Version ControlIntroduction to Version Control
Introduction to Version Control
 
Clean architecture
Clean architectureClean architecture
Clean architecture
 

Similar a Building a Pyramid: Symfony Testing Strategies

Finding the Right Testing Tool for the Job
Finding the Right Testing Tool for the JobFinding the Right Testing Tool for the Job
Finding the Right Testing Tool for the JobCiaranMcNulty
 
Agile methodologies based on BDD and CI by Nikolai Shevchenko
Agile methodologies based on BDD and CI by Nikolai ShevchenkoAgile methodologies based on BDD and CI by Nikolai Shevchenko
Agile methodologies based on BDD and CI by Nikolai ShevchenkoMoldova ICT Summit
 
A test framework out of the box - Geb for Web and mobile
A test framework out of the box - Geb for Web and mobileA test framework out of the box - Geb for Web and mobile
A test framework out of the box - Geb for Web and mobileGlobalLogic Ukraine
 
Testing C# and ASP.net using Ruby
Testing C# and ASP.net using RubyTesting C# and ASP.net using Ruby
Testing C# and ASP.net using RubyBen Hall
 
Automated integration tests for ajax applications (с. карпушин, auriga)
Automated integration tests for ajax applications (с. карпушин, auriga)Automated integration tests for ajax applications (с. карпушин, auriga)
Automated integration tests for ajax applications (с. карпушин, auriga)Mobile Developer Day
 
Serverless Angular, Material, Firebase and Google Cloud applications
Serverless Angular, Material, Firebase and Google Cloud applicationsServerless Angular, Material, Firebase and Google Cloud applications
Serverless Angular, Material, Firebase and Google Cloud applicationsLoiane Groner
 
Better Testing With PHP Unit
Better Testing With PHP UnitBetter Testing With PHP Unit
Better Testing With PHP Unitsitecrafting
 
How to optimize background processes - when Sylius meets Blackfire
How to optimize background processes - when Sylius meets BlackfireHow to optimize background processes - when Sylius meets Blackfire
How to optimize background processes - when Sylius meets BlackfireŁukasz Chruściel
 
Altitude San Francisco 2018: Testing with Fastly Workshop
Altitude San Francisco 2018: Testing with Fastly WorkshopAltitude San Francisco 2018: Testing with Fastly Workshop
Altitude San Francisco 2018: Testing with Fastly WorkshopFastly
 
Selenium my sql and junit user guide
Selenium my sql and junit user guideSelenium my sql and junit user guide
Selenium my sql and junit user guideFahad Shiekh
 
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
3 Ways to test your ColdFusion API - 2017 Adobe CF SummitOrtus Solutions, Corp
 
Security Testing
Security TestingSecurity Testing
Security TestingKiran Kumar
 
Code your Own: Authentication Provider for Blackboard Learn
Code your Own: Authentication Provider for Blackboard LearnCode your Own: Authentication Provider for Blackboard Learn
Code your Own: Authentication Provider for Blackboard LearnDan Rinzel
 
Asp netmvc e03
Asp netmvc e03Asp netmvc e03
Asp netmvc e03Yu GUAN
 
Workshop: Building Vaadin add-ons
Workshop: Building Vaadin add-onsWorkshop: Building Vaadin add-ons
Workshop: Building Vaadin add-onsSami Ekblad
 
Bdd with Cucumber and Mocha
Bdd with Cucumber and MochaBdd with Cucumber and Mocha
Bdd with Cucumber and MochaAtish Narlawar
 
BDD, ATDD, Page Objects: The Road to Sustainable Web Testing
BDD, ATDD, Page Objects: The Road to Sustainable Web TestingBDD, ATDD, Page Objects: The Road to Sustainable Web Testing
BDD, ATDD, Page Objects: The Road to Sustainable Web TestingJohn Ferguson Smart Limited
 
Google external login setup in ASP (1).pdf
Google external login setup in ASP  (1).pdfGoogle external login setup in ASP  (1).pdf
Google external login setup in ASP (1).pdffindandsolve .com
 

Similar a Building a Pyramid: Symfony Testing Strategies (20)

Finding the Right Testing Tool for the Job
Finding the Right Testing Tool for the JobFinding the Right Testing Tool for the Job
Finding the Right Testing Tool for the Job
 
Agile methodologies based on BDD and CI by Nikolai Shevchenko
Agile methodologies based on BDD and CI by Nikolai ShevchenkoAgile methodologies based on BDD and CI by Nikolai Shevchenko
Agile methodologies based on BDD and CI by Nikolai Shevchenko
 
A test framework out of the box - Geb for Web and mobile
A test framework out of the box - Geb for Web and mobileA test framework out of the box - Geb for Web and mobile
A test framework out of the box - Geb for Web and mobile
 
Testing C# and ASP.net using Ruby
Testing C# and ASP.net using RubyTesting C# and ASP.net using Ruby
Testing C# and ASP.net using Ruby
 
Automated integration tests for ajax applications (с. карпушин, auriga)
Automated integration tests for ajax applications (с. карпушин, auriga)Automated integration tests for ajax applications (с. карпушин, auriga)
Automated integration tests for ajax applications (с. карпушин, auriga)
 
Serverless Angular, Material, Firebase and Google Cloud applications
Serverless Angular, Material, Firebase and Google Cloud applicationsServerless Angular, Material, Firebase and Google Cloud applications
Serverless Angular, Material, Firebase and Google Cloud applications
 
Clean tests good tests
Clean tests   good testsClean tests   good tests
Clean tests good tests
 
Better Testing With PHP Unit
Better Testing With PHP UnitBetter Testing With PHP Unit
Better Testing With PHP Unit
 
How to optimize background processes - when Sylius meets Blackfire
How to optimize background processes - when Sylius meets BlackfireHow to optimize background processes - when Sylius meets Blackfire
How to optimize background processes - when Sylius meets Blackfire
 
Altitude San Francisco 2018: Testing with Fastly Workshop
Altitude San Francisco 2018: Testing with Fastly WorkshopAltitude San Francisco 2018: Testing with Fastly Workshop
Altitude San Francisco 2018: Testing with Fastly Workshop
 
Selenium my sql and junit user guide
Selenium my sql and junit user guideSelenium my sql and junit user guide
Selenium my sql and junit user guide
 
Evolve your coding with some BDD
Evolve your coding with some BDDEvolve your coding with some BDD
Evolve your coding with some BDD
 
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
 
Security Testing
Security TestingSecurity Testing
Security Testing
 
Code your Own: Authentication Provider for Blackboard Learn
Code your Own: Authentication Provider for Blackboard LearnCode your Own: Authentication Provider for Blackboard Learn
Code your Own: Authentication Provider for Blackboard Learn
 
Asp netmvc e03
Asp netmvc e03Asp netmvc e03
Asp netmvc e03
 
Workshop: Building Vaadin add-ons
Workshop: Building Vaadin add-onsWorkshop: Building Vaadin add-ons
Workshop: Building Vaadin add-ons
 
Bdd with Cucumber and Mocha
Bdd with Cucumber and MochaBdd with Cucumber and Mocha
Bdd with Cucumber and Mocha
 
BDD, ATDD, Page Objects: The Road to Sustainable Web Testing
BDD, ATDD, Page Objects: The Road to Sustainable Web TestingBDD, ATDD, Page Objects: The Road to Sustainable Web Testing
BDD, ATDD, Page Objects: The Road to Sustainable Web Testing
 
Google external login setup in ASP (1).pdf
Google external login setup in ASP  (1).pdfGoogle external login setup in ASP  (1).pdf
Google external login setup in ASP (1).pdf
 

Más de CiaranMcNulty

Greener web development at PHP London
Greener web development at PHP LondonGreener web development at PHP London
Greener web development at PHP LondonCiaranMcNulty
 
Doodle Driven Development
Doodle Driven DevelopmentDoodle Driven Development
Doodle Driven DevelopmentCiaranMcNulty
 
Behat Best Practices with Symfony
Behat Best Practices with SymfonyBehat Best Practices with Symfony
Behat Best Practices with SymfonyCiaranMcNulty
 
Behat Best Practices
Behat Best PracticesBehat Best Practices
Behat Best PracticesCiaranMcNulty
 
Behat Best Practices with Symfony
Behat Best Practices with SymfonyBehat Best Practices with Symfony
Behat Best Practices with SymfonyCiaranMcNulty
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through ExamplesCiaranMcNulty
 
Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016CiaranMcNulty
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through ExamplesCiaranMcNulty
 
Conscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHPConscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHPCiaranMcNulty
 
TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016CiaranMcNulty
 
Fly In Style (without splashing out)
Fly In Style (without splashing out)Fly In Style (without splashing out)
Fly In Style (without splashing out)CiaranMcNulty
 
Why Your Test Suite Sucks - PHPCon PL 2015
Why Your Test Suite Sucks - PHPCon PL 2015Why Your Test Suite Sucks - PHPCon PL 2015
Why Your Test Suite Sucks - PHPCon PL 2015CiaranMcNulty
 
Driving Design through Examples - PhpCon PL 2015
Driving Design through Examples - PhpCon PL 2015Driving Design through Examples - PhpCon PL 2015
Driving Design through Examples - PhpCon PL 2015CiaranMcNulty
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through ExamplesCiaranMcNulty
 
Why Your Test Suite Sucks
Why Your Test Suite SucksWhy Your Test Suite Sucks
Why Your Test Suite SucksCiaranMcNulty
 
Driving Design with PhpSpec
Driving Design with PhpSpecDriving Design with PhpSpec
Driving Design with PhpSpecCiaranMcNulty
 
Using HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless IntegrationUsing HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless IntegrationCiaranMcNulty
 

Más de CiaranMcNulty (19)

Greener web development at PHP London
Greener web development at PHP LondonGreener web development at PHP London
Greener web development at PHP London
 
Doodle Driven Development
Doodle Driven DevelopmentDoodle Driven Development
Doodle Driven Development
 
Behat Best Practices with Symfony
Behat Best Practices with SymfonyBehat Best Practices with Symfony
Behat Best Practices with Symfony
 
Behat Best Practices
Behat Best PracticesBehat Best Practices
Behat Best Practices
 
Behat Best Practices with Symfony
Behat Best Practices with SymfonyBehat Best Practices with Symfony
Behat Best Practices with Symfony
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through Examples
 
Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016
 
Conscious Coupling
Conscious CouplingConscious Coupling
Conscious Coupling
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through Examples
 
Conscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHPConscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHP
 
TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016
 
Fly In Style (without splashing out)
Fly In Style (without splashing out)Fly In Style (without splashing out)
Fly In Style (without splashing out)
 
Why Your Test Suite Sucks - PHPCon PL 2015
Why Your Test Suite Sucks - PHPCon PL 2015Why Your Test Suite Sucks - PHPCon PL 2015
Why Your Test Suite Sucks - PHPCon PL 2015
 
Driving Design through Examples - PhpCon PL 2015
Driving Design through Examples - PhpCon PL 2015Driving Design through Examples - PhpCon PL 2015
Driving Design through Examples - PhpCon PL 2015
 
TDD with PhpSpec
TDD with PhpSpecTDD with PhpSpec
TDD with PhpSpec
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through Examples
 
Why Your Test Suite Sucks
Why Your Test Suite SucksWhy Your Test Suite Sucks
Why Your Test Suite Sucks
 
Driving Design with PhpSpec
Driving Design with PhpSpecDriving Design with PhpSpec
Driving Design with PhpSpec
 
Using HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless IntegrationUsing HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless Integration
 

Último

Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfhans926745
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 

Último (20)

Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 

Building a Pyramid: Symfony Testing Strategies

  • 1. Building a Test Pyramid: Symfony testing strategies with Ciaran McNulty
  • 2. Before we start: You must test your applications!
  • 3. What kind of tests to use? » Manual testing » Acceptance testing » Unit testing » Integration testing » End-to-end testing » Black box / white box
  • 4. What tools to use? » PHPUnit » PhpSpec » Behat » Codeception » BrowserKit / Webcrawler
  • 5. Question: Why can't someone tell me which one to use?
  • 6. Answer: Because there is no best answer that fits all cases You have to find the
  • 7. Testing different layers Introducing the pyramid » Defined by Mike Cohn in Succeeding with Agile » For understanding different layers of testing
  • 8.
  • 9. UI layer tests » Test the whole application end-to-end » Sensitive to UI changes » Aligned with acceptance criteria » Does not require good code » Probably slow e.g. Open a browser, fill in the form and submit it
  • 10. Service layer tests » Test the application logic by making service calls » Faster than UI testing » Aligned with acceptance criteria » Mostly written in the target language » Requires high-level services to exist e.g. Instantiate the Calculator service and get it to add two numbers
  • 11. Unit level tests » Test individual classes » Much faster than service level testing » Very fine level of detail » Requires good design
  • 12. Why a pyramid? » Each layer builds on the one below it » Lower layers are faster to run » Higher levels are slower and more brittle » Have more tests at the bottom than at the top
  • 13. Why do you want tests? The answer will affect the type of tests you write
  • 14. If you want existing features from breaking ... write Regression Tests
  • 15. Regression tests » Check that behaviour hasn't changed » Easiest to apply at the UI level » ALL tests become regression tests eventually
  • 16. 'Legacy' code class BasketController extends Controller { public function addAction(Request $request) { $productId = $request->attributes->get('product_id'); $basket = $request->getSession()->get('basket_context')->getCurrent(); $products = $basket->getProducts(); $products[] = $productId; $basket->setProducts($products); return $this->render('::basket.html.twig', ['basket' => $basket]); } }
  • 17. Regression testing with PHPUnit + BrowserKit class PostControllerTest extends WebTestCase { public function testShowPost() { $client = static::createClient(); $crawler = $client->request('GET', '/products/1234'); $form = $crawler->selectButton('Add to basket')->form(); $client->submit($form, ['id'=>1234]); $product = $crawler->filter('html:contains("Product: 1234")'); $this->assertCount(1, $product); } }
  • 18. Regression testing with Codeception $I = new AcceptanceTester($scenario); $I->amOnPage('/products/1234'); $I->click('Add to basket'); $I->see('Product: 1234');
  • 19. Regression testing with Behat + MinkExtension Scenario: Adding a product to the basket Given I am on "/product/1234" When I click "Add to Basket" Then I should see "Product: 1234"
  • 20. Regression testing with Ghost Inspector
  • 21. When regression testing » Use a tool that gets you coverage quickly and easily » Plan to phase out regression tests later » Lean towards testing end-to-end » Recognise they will be hard to maintain
  • 22. If you want to match customer requirements better ... write Acceptance Tests
  • 23. Acceptance Tests » Check the system does what the customer wants » Are aligned with customer language and intention » Write them in English (or another language) first » Can be tested at the UI or Service level
  • 24. Start with an example-led conversation ... before you start working on it ... but not too long before
  • 25. » "What should the system do when X happens?" » "Does Y always happen when X?" » "What assumptions Z are causing Y to be the outcome?" » "Given Z when X then Y" » "What other things aside from Y might happen?" » "What if...?"
  • 26. Write the examples out in business- readable tests Try and make the code look like the natural conversation you had
  • 27. Easiest to test through the User Interface
  • 28. UI Acceptance testing with PHPUnit + BrowserKit class PostControllerTest extends WebTestCase { public function testAddingProductToTheBasket() { $this->addProductToBasket(1234); $this->productShouldBeShownInBasket(1234); } private function addProductToBasket($productId) { //... browser automation code } private function productShouldBeShownInBasket($productId) { //... browser automation code } }
  • 29. UI Acceptance testing with Codeception $I = new AcceptanceTester($scenario); $I->amGoingTo('Add a product to the basket'); $I->amOnPage('/products/1234'); $I->click('Add to basket'); $I->expectTo('see the product in the basket'); $I->see('Product: 1234');
  • 30. UI Acceptance testing with Behat + MinkExtension Scenario: Adding a product to the basket When I add product 1234 to the basket Then I should see product 1234 in the basket
  • 31. UI Acceptance testing with Behat + MinkExtension /** * @When I add product :productId to the basket */ public function iAddProduct($productId) { $this->visitUrl('/product/' . $productId); $this->getSession()->clickButton('Add to Basket'); } /** * @Then I should see product :productId in the basket */ public function iShouldSeeProduct($productId) { $this->assertSession()->elementContains('css', '#basket', 'Product: ' . $productId); }
  • 32. Acceptance testing through the UI is slow and brittle To test at the service layer, we need to introduce services
  • 33. 'Legacy' code class BasketController extends Controller { public function addAction(Request $request) { $productId = $request->attributes->get('product_id'); $basket = $request->getSession()->get('basket_context')->getCurrent(); $products = $basket->getProducts(); $products[] = $productId; $basket->setProducts($products); return $this->render('::basket.html.twig', ['basket' => $basket]); } }
  • 34. 'Service-oriented' code class BasketController extends Controller { public function addAction(Request $request) { $basket = $this->get('basket_context')->getCurrent(); $productId = $request->attributes->get('product_id'); $basket->addProduct($productId); return $this->render('::basket.html.twig', ['basket' => $basket]); } }
  • 35. A very small change but now the business logic is out of the controller
  • 36. Service layer Acceptance testing with PHPUnit class PostControllerTest extends PHPUnit_Framework_TestCase { public function testAddingProductToTheBasket() { $basket = new Basket(new BasketArrayStorage()); $basket->addProduct(1234); $this->assertContains(1234, $basket->getProducts()); } }
  • 37. Service layer acceptance testing with Behat + MinkExtension Scenario: Adding a product to the basket When I add product 1234 to the basket Then I should see product 1234 in the basket
  • 38. Service layer acceptance testing with Behat /** * @When I add product :productId to the basket */ public function iAddProduct($productId) { $this->basket = new Basket(new BasketArrayStorage()); $this->basket->addProduct($productId); } /** * @Then I should see product :productId in the basket */ public function iShouldSeeProduct($productId) { assert(in_array($productId, $this->basket->getProducts()); }
  • 39. When all of the acceptance tests are running against the Service layer ... how many also need to be run through the UI?
  • 40. Symfony is a controller for your app
  • 41. If you test everything through services ... you only need enough UI tests to be sure the UI is
  • 42. Multiple Behat suites Scenario: Adding a product to the basket When I add product 1234 to the basket Then I should see product 1234 in the basket Scenario: Adding a product that is already there Given I have already added product 1234 to the basket When I add product 1234 to the basket Then I should see 2 instances of product 1234 in the basket @ui Scenario: Adding two products to my basket Given I have already added product 4567 to the basket When I add product 1234 to the basket Then I should see product 4567 in the basket And I should also see product 1234 in the basket
  • 43. Multiple Behat suites default: suites: ui: contexts: [ UiContext ] filters: { tags: @ui } service: contexts: [ ServiceContext ]
  • 44. If you want the design of your code to be better ... write Unit Tests
  • 45. Unit Tests » Check that a class does what you expect » Use a tool that makes it easy to test classes in isolation » Move towards writing them first » Unit tests force you to have good design » Probably too small to reflect acceptance criteria
  • 46. Unit tests are too granular Customer: "The engine needs to produce 500bhp" Engineer: "What should the diameter of the main drive shaft be?"
  • 47. Unit testing in PHPUnit class BasketTest extends PHPUnit_Framework_Testcase { public function testGetsProductsFromStorage() { $storage = $this->getMock('BasketStorage'); $storage->expect($this->once()) ->method('persistProducts') ->with([1234]); $basket = new Basket($storage); $basket->addProduct(1234); } }
  • 48. Unit testing in PhpSpec class BasketSpec extends ObjectBehavior { function it_gets_products_from_storage(BasketStorage $storage) { $this->beConstructedWith($storage); $this->addProduct(1234); $storage->persistProducts([1234])->shouldHaveBeenCalled([1234]); } }
  • 49. Unit test ... code that is responsible for business logic ... not code that interacts with infrastructure including Symfony
  • 50. You can unit test interactions with Symfony (e.g. controllers) You shouldn't need to if you have acceptance tests
  • 52. Unit testing third party dependencies class FileHandlerSpec extends ObjectBehaviour { public function it_uploads_data_to_the_cloud_when_valid( CloudApi $client, FileValidator $validator, File $file ) { $this->beConstructedWith($client, $validator); $validator->validate($file)->willReturn(true); $client->startUpload()->shouldBeCalled(); $client->uploadData(Argument::any())->shouldBeCalled(); $client->uploadSuccessful()->willReturn(true); $this->process($file)->shouldReturn(true); } }
  • 56. class FileHandlerSpec extends ObjectBehaviour { public function it_uploads_data_to_the_cloud_when_valid( FileStore $filestore, FileValidator $validator, File $file ) { $this->beConstructedWith($filestore, $validator); $validator->validate($file)->willReturn(true); $this->process($file); $filestore->store($file)->shouldHaveBeenCalled(); } }
  • 58. class CloudFilestoreTest extends PHPUnit_Framework_TestCase { function testItStoresFiles() { $testCredentials = … $file = new File(…); $apiClient = new CloudApi($testCredentials); $filestore = new CloudFileStore($apiClient); $filestore->store($file); $this->assertTrue($apiClient->fileExists(…)); } }
  • 61. Have isolated unit- tested objects representing your core business logic 10,000s of tests running in <10ms each
  • 62. Have acceptance tests at the service level 1,000s of tests running in <100ms each
  • 63. Have the bare minimum of acceptance tests at the UI level 10s of tests running in <10s each