SlideShare a Scribd company logo
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

More Related Content

What's hot

Second Level Cache in JPA Explained
Second Level Cache in JPA ExplainedSecond Level Cache in JPA Explained
Second Level Cache in JPA Explained
Patrycja Wegrzynowicz
 
L'API Collector dans tous ses états
L'API Collector dans tous ses étatsL'API Collector dans tous ses états
L'API Collector dans tous ses états
José Paumard
 
날로 먹는 Django admin 활용
날로 먹는 Django admin 활용날로 먹는 Django admin 활용
날로 먹는 Django admin 활용
KyeongMook "Kay" Cha
 
What is JavaScript? Edureka
What is JavaScript? EdurekaWhat is JavaScript? Edureka
What is JavaScript? Edureka
Edureka!
 
Node Architecture and Getting Started with Express
Node Architecture and Getting Started with ExpressNode Architecture and Getting Started with Express
Node Architecture and Getting Started with Express
jguerrero999
 
유니티 REST API를 사용한 파이어 베이스의 데이터 베이스 사용.
유니티 REST API를 사용한 파이어 베이스의 데이터 베이스 사용.유니티 REST API를 사용한 파이어 베이스의 데이터 베이스 사용.
유니티 REST API를 사용한 파이어 베이스의 데이터 베이스 사용.
ssuser6dd171
 
Celery의 빛과 그림자
Celery의 빛과 그림자Celery의 빛과 그림자
Celery의 빛과 그림자
Minyoung Jeong
 
HTL(Sightly) - All you need to know
HTL(Sightly) - All you need to knowHTL(Sightly) - All you need to know
HTL(Sightly) - All you need to knowPrabhdeep Singh
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with Spring
Joshua Long
 
Java 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJava 8-streams-collectors-patterns
Java 8-streams-collectors-patterns
José Paumard
 
[오픈소스컨설팅]Spring MVC
[오픈소스컨설팅]Spring MVC [오픈소스컨설팅]Spring MVC
[오픈소스컨설팅]Spring MVC
Ji-Woong Choi
 
Spring Interview Questions and Answers | Spring Tutorial | Spring Framework T...
Spring Interview Questions and Answers | Spring Tutorial | Spring Framework T...Spring Interview Questions and Answers | Spring Tutorial | Spring Framework T...
Spring Interview Questions and Answers | Spring Tutorial | Spring Framework T...
Edureka!
 
An Introduction to ReactJS
An Introduction to ReactJSAn Introduction to ReactJS
An Introduction to ReactJS
All Things Open
 
Ajax Under The Hood
Ajax Under The HoodAjax Under The Hood
Ajax Under The Hood
WO Community
 
learn what React JS is & why we should use React JS .
learn what React JS is & why we should use React JS .learn what React JS is & why we should use React JS .
learn what React JS is & why we should use React JS .
paradisetechsoftsolutions
 
NestJS
NestJSNestJS
NestJS
Wilson Su
 
Laravel Design Patterns
Laravel Design PatternsLaravel Design Patterns
Laravel Design Patterns
Bobby Bouwmann
 
Docker 간단 개념 / Docker 를 이용한 MSA 기반의 Spring Boot 프로젝트 - DSmentoring 정다운
Docker 간단 개념 / Docker 를 이용한 MSA 기반의 Spring Boot 프로젝트 - DSmentoring 정다운Docker 간단 개념 / Docker 를 이용한 MSA 기반의 Spring Boot 프로젝트 - DSmentoring 정다운
Docker 간단 개념 / Docker 를 이용한 MSA 기반의 Spring Boot 프로젝트 - DSmentoring 정다운
다운 정
 
간단한 블로그를 만들며 Django 이해하기
간단한 블로그를 만들며 Django 이해하기간단한 블로그를 만들며 Django 이해하기
간단한 블로그를 만들며 Django 이해하기
Kyoung Up Jung
 

What's hot (20)

Second Level Cache in JPA Explained
Second Level Cache in JPA ExplainedSecond Level Cache in JPA Explained
Second Level Cache in JPA Explained
 
L'API Collector dans tous ses états
L'API Collector dans tous ses étatsL'API Collector dans tous ses états
L'API Collector dans tous ses états
 
Express node js
Express node jsExpress node js
Express node js
 
날로 먹는 Django admin 활용
날로 먹는 Django admin 활용날로 먹는 Django admin 활용
날로 먹는 Django admin 활용
 
What is JavaScript? Edureka
What is JavaScript? EdurekaWhat is JavaScript? Edureka
What is JavaScript? Edureka
 
Node Architecture and Getting Started with Express
Node Architecture and Getting Started with ExpressNode Architecture and Getting Started with Express
Node Architecture and Getting Started with Express
 
유니티 REST API를 사용한 파이어 베이스의 데이터 베이스 사용.
유니티 REST API를 사용한 파이어 베이스의 데이터 베이스 사용.유니티 REST API를 사용한 파이어 베이스의 데이터 베이스 사용.
유니티 REST API를 사용한 파이어 베이스의 데이터 베이스 사용.
 
Celery의 빛과 그림자
Celery의 빛과 그림자Celery의 빛과 그림자
Celery의 빛과 그림자
 
HTL(Sightly) - All you need to know
HTL(Sightly) - All you need to knowHTL(Sightly) - All you need to know
HTL(Sightly) - All you need to know
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with Spring
 
Java 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJava 8-streams-collectors-patterns
Java 8-streams-collectors-patterns
 
[오픈소스컨설팅]Spring MVC
[오픈소스컨설팅]Spring MVC [오픈소스컨설팅]Spring MVC
[오픈소스컨설팅]Spring MVC
 
Spring Interview Questions and Answers | Spring Tutorial | Spring Framework T...
Spring Interview Questions and Answers | Spring Tutorial | Spring Framework T...Spring Interview Questions and Answers | Spring Tutorial | Spring Framework T...
Spring Interview Questions and Answers | Spring Tutorial | Spring Framework T...
 
An Introduction to ReactJS
An Introduction to ReactJSAn Introduction to ReactJS
An Introduction to ReactJS
 
Ajax Under The Hood
Ajax Under The HoodAjax Under The Hood
Ajax Under The Hood
 
learn what React JS is & why we should use React JS .
learn what React JS is & why we should use React JS .learn what React JS is & why we should use React JS .
learn what React JS is & why we should use React JS .
 
NestJS
NestJSNestJS
NestJS
 
Laravel Design Patterns
Laravel Design PatternsLaravel Design Patterns
Laravel Design Patterns
 
Docker 간단 개념 / Docker 를 이용한 MSA 기반의 Spring Boot 프로젝트 - DSmentoring 정다운
Docker 간단 개념 / Docker 를 이용한 MSA 기반의 Spring Boot 프로젝트 - DSmentoring 정다운Docker 간단 개념 / Docker 를 이용한 MSA 기반의 Spring Boot 프로젝트 - DSmentoring 정다운
Docker 간단 개념 / Docker 를 이용한 MSA 기반의 Spring Boot 프로젝트 - DSmentoring 정다운
 
간단한 블로그를 만들며 Django 이해하기
간단한 블로그를 만들며 Django 이해하기간단한 블로그를 만들며 Django 이해하기
간단한 블로그를 만들며 Django 이해하기
 

Similar to 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 Job
CiaranMcNulty
 
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 mobile
GlobalLogic 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 Ruby
Ben 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 applications
Loiane Groner
 
Clean tests good tests
Clean tests   good testsClean tests   good tests
Clean tests good tests
Shopsys Framework
 
Better Testing With PHP Unit
Better Testing With PHP UnitBetter Testing With PHP Unit
Better Testing With PHP Unit
sitecrafting
 
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 Workshop
Fastly
 
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
Fahad Shiekh
 
Evolve your coding with some BDD
Evolve your coding with some BDDEvolve your coding with some BDD
Evolve your coding with some BDD
Ortus Solutions, Corp
 
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
Ortus Solutions, Corp
 
From framework coupled code to #microservices through #DDD /by @codelytv
From framework coupled code to #microservices through #DDD /by @codelytvFrom framework coupled code to #microservices through #DDD /by @codelytv
From framework coupled code to #microservices through #DDD /by @codelytv
CodelyTV
 
Security Testing
Security TestingSecurity Testing
Security Testing
Kiran 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 Learn
Dan Rinzel
 
Asp netmvc e03
Asp netmvc e03Asp netmvc e03
Asp netmvc e03
Yu GUAN
 
Workshop: Building Vaadin add-ons
Workshop: Building Vaadin add-onsWorkshop: Building Vaadin add-ons
Workshop: Building Vaadin add-ons
Sami Ekblad
 
Bdd with Cucumber and Mocha
Bdd with Cucumber and MochaBdd with Cucumber and Mocha
Bdd with Cucumber and Mocha
Atish 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 Testing
John Ferguson Smart Limited
 

Similar to 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
 
From framework coupled code to #microservices through #DDD /by @codelytv
From framework coupled code to #microservices through #DDD /by @codelytvFrom framework coupled code to #microservices through #DDD /by @codelytv
From framework coupled code to #microservices through #DDD /by @codelytv
 
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
 

More from CiaranMcNulty

Greener web development at PHP London
Greener web development at PHP LondonGreener web development at PHP London
Greener web development at PHP London
CiaranMcNulty
 
Doodle Driven Development
Doodle Driven DevelopmentDoodle Driven Development
Doodle Driven Development
CiaranMcNulty
 
Behat Best Practices with Symfony
Behat Best Practices with SymfonyBehat Best Practices with Symfony
Behat Best Practices with Symfony
CiaranMcNulty
 
Behat Best Practices
Behat Best PracticesBehat Best Practices
Behat Best Practices
CiaranMcNulty
 
Behat Best Practices with Symfony
Behat Best Practices with SymfonyBehat Best Practices with Symfony
Behat Best Practices with Symfony
CiaranMcNulty
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through Examples
CiaranMcNulty
 
Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016
CiaranMcNulty
 
Conscious Coupling
Conscious CouplingConscious Coupling
Conscious Coupling
CiaranMcNulty
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through Examples
CiaranMcNulty
 
Conscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHPConscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHP
CiaranMcNulty
 
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
CiaranMcNulty
 
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 2015
CiaranMcNulty
 
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
CiaranMcNulty
 
TDD with PhpSpec
TDD with PhpSpecTDD with PhpSpec
TDD with PhpSpec
CiaranMcNulty
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through Examples
CiaranMcNulty
 
Why Your Test Suite Sucks
Why Your Test Suite SucksWhy Your Test Suite Sucks
Why Your Test Suite Sucks
CiaranMcNulty
 
Driving Design with PhpSpec
Driving Design with PhpSpecDriving Design with PhpSpec
Driving Design with PhpSpec
CiaranMcNulty
 
Using HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless IntegrationUsing HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless Integration
CiaranMcNulty
 

More from 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
 

Recently uploaded

Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
DianaGray10
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
Paul Groth
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
Product School
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User Group
CatarinaPereira64715
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
Elena Simperl
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
Product School
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Thijs Feryn
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
DianaGray10
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 

Recently uploaded (20)

Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User Group
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 

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