SlideShare a Scribd company logo
1 of 94
Best Practice Testing with  Lime 2 Bernhard Schussek
Who am I? ,[object Object]
Lead Developer at 2bePUBLISHED ,[object Object]
Search Engine Marketing & Optimization
since 2007 ,[object Object]
Recently: Symfony Core Contributor
Part I The Interactive Stuff
What is important? Brainstorming
Things to Keep in Mind ,[object Object]
Things to Keep in Mind ,[object Object]
Test Frequently!
Things to Keep in Mind ,[object Object]
Test Frequently!
Performance
Things to Keep in Mind ,[object Object]
Test Frequently!
Performance
Reliability ,[object Object]
Things to Keep in Mind ,[object Object]
Test Frequently!
Performance
Reliability ,[object Object],[object Object]
Part II Testing Strategies
4 Phase Test
The Test Fixture
Test Isolation
How to Write Testable Code?
Fake Objects
Functional vs. Unit Tests
Creation and Helper Functions
Cukeet
Testing Strategies - Cukeet ,[object Object],[object Object],[object Object],[object Object]
Categories
Images
...
Testing Strategies – 4 Phase Test // @Test: resize() resizes the thumbnail copy( 'data/fixtures/test.png' ,  'web/uploads/test.png' ); $thumbnail  =  new  CukeetThumbnail( 'web/uploads/test.png' ); $thumbnail ->resize( 100 ,  100 ); $size  = getimagesize( $thumbnail ->getPath()); $t ->is( $size ,  array ( 100 ,  100 ),  'The image has been resized' ); unlink( 'web/uploads/test.png' ); unset( $thumbnail ); Our Tested Class
Testing Strategies – 4 Phase Test // @Test: resize() resizes the thumbnail copy( 'data/fixtures/test.png' ,  'web/uploads/test.png' ); $thumbnail  =  new  CukeetThumbnail( 'web/uploads/test.png' ); $thumbnail ->resize( 100 ,  100 ); $size  = getimagesize( $thumbnail ->getPath()); $t ->is( $size ,  array ( 100 ,  100 ),  'The image has been resized' ); unlink( 'web/uploads/test.png' ); unset( $thumbnail ); Fixture Setup
Testing Strategies – 4 Phase Test // @Test: resize() resizes the thumbnail copy( 'data/fixtures/test.png' ,  'web/uploads/test.png' ); $thumbnail  =  new  CukeetThumbnail( 'web/uploads/test.png' ); $thumbnail ->resize( 100 ,  100 ); $size  = getimagesize( $thumbnail ->getPath()); $t ->is( $size ,  array ( 100 ,  100 ),  'The image has been resized' ); unlink( 'web/uploads/test.png' ); unset( $thumbnail ); Test Execution
Testing Strategies – 4 Phase Test // @Test: resize() resizes the thumbnail copy( 'data/fixtures/test.png' ,  'web/uploads/test.png' ); $thumbnail  =  new  CukeetThumbnail( 'web/uploads/test.png' ); $thumbnail ->resize( 100 ,  100 ); $size  = getimagesize( $thumbnail ->getPath()); $t ->is( $size ,  array ( 100 ,  100 ),  'The image has been resized' ); unlink( 'web/uploads/test.png' ); unset( $thumbnail ); Result Verification
Testing Strategies – 4 Phase Test // @Test: resize() resizes the thumbnail copy( 'data/fixtures/test.png' ,  'web/uploads/test.png' ); $thumbnail  =  new  CukeetThumbnail( 'web/uploads/test.png' ); $thumbnail ->resize( 100 ,  100 ); $size  = getimagesize( $thumbnail ->getPath()); $t ->is( $size ,  array ( 100 ,  100 ),  'The image has been resized' ); unlink( 'web/uploads/test.png' ); unset( $thumbnail ); Fixture Teardown
Testing Strategies – 4 Phase Test ,[object Object],[object Object]
Test execution
Result Verification
Fixture teardown ,[object Object]
Make it obvious  what  you are testing
Testing Strategies – 4 Phase Test // @Test: resize() resizes the thumbnail // setup copy( 'data/fixtures/test.png' ,  'web/uploads/test.png' ); // test $thumbnail  =  new  CukeetThumbnail( 'web/uploads/test.png' ); $thumbnail ->resize( 100 ,  100 ); // assertions $size  = getimagesize( $thumbnail ->getPath()); $t ->is( $size ,  array ( 100 ,  100 ),  'The image has been resized' ); // teardown unlink( 'web/uploads/test.png' ); unset( $thumbnail ); Use Comments!
The Test Fixture
Testing Strategies – The Test Fixture ,[object Object],[object Object],[object Object]
Fresh Fixture
Testing Strategies – The Test Fixture Global Fixture Fresh Fixture Fixture Setup test.png, new CukeetThumbnail() Test 1 Test 2 Test 3 Test 4 Fixture Setup test.png, new CukeetThumbnail() Test 1 Test 2 Fixture Setup test.png, new CukeetThumbnail() Fixture Setup
Test Isolation
Lime 2 Annotations
Testing Strategies – Annotations ,[object Object],[object Object],[object Object],[object Object],[object Object]
@After
@BeforeAll
@AfterAll
Testing Strategies – Annotations // @Before copy( 'data/fixtures/test.png' ,  'web/uploads/test.png' ); $thumbnail  =  new  CukeetThumbnail( 'web/uploads/test.png' ); // @After unlink( 'web/uploads/test.png' ); unset( $thumbnail ); // @Test: resize() resizes the thumbnail $thumbnail ->resize( 100 ,  100 ); $size  = getimagesize( $thumbnail ->getPath()); $t ->is( $size ,  array ( 100 ,  100 ),  'The image has been resized' );
Testing Strategies - Annotations ,[object Object],[object Object]
Fixtures can be built and destroyed automatically
The chance of interacting tests is reduced
Testing Strategies – xUnit Style Test Class class  CukeetThumbnailTest  extends  LimeTestCase { private   $thumbnail ; public   function  setup() { copy( 'data/fixtures/test.png' ,  'web/uploads/test.png' ); $this ->thumbnail =  new  CukeetThumbnail( 'web/uploads/test.png' ); } public   function  teardown() { unlink( 'web/uploads/test.png' ); unset( $this ->thumbnail); } public   function  testTheThumbnailCanBeResized() {} } Same As With Annotations
How to Write Testable Code?
Testing Strategies – How to Write Testable Code class  CukeetRecipe { public   function  save() { $user  = sfContext::getInstance()->getUser(); if  (! $user ->hasCredential( 'admin' )) { throw   new  RuntimeException( 'No permission!' ); } } }
Testing Strategies – How to Write Testable Code class  CukeetRecipe { public   function  save() { $user  = sfContext::getInstance()->getUser(); if  (! $user ->hasCredential( 'admin' )) { throw   new  RuntimeException( 'No permission!' ); } } } Uh oh...
Expensive Operation
Unexpected Side-Effects
Lose Control
Testing Strategies – How to Write Testable Code? ? Test Tested Class Dependency
Dependency Injection
Testing Strategies – Dependency Injection ,[object Object]
Testing Strategies – Constructor Injection class  CukeetRecipe { private   $user ; public   function  __construct(sfBasicSecurityUser  $user ) { $this ->user =  $user ; } public   function  save() { if  (! $this ->user->hasCredential( 'admin' )) { throw   new  RuntimeException( 'No permission!' ); } }
Testing Strategies – Dependency Injection // @Before $user  =  new  sfBasicSecurityUser(); $recipe  =  new  CukeetRecipe( $user ); // @Test: Users with credential 'admin' can save $user ->addCredential( 'admin' ); $recipe ->save( $user ); // @Test: Normal users cannot save $t ->expect( 'RuntimeException' ); $recipe ->save( $user );
Testing Strategies – How to Write Testable Code? Test Tested Class Dependency
Testing Strategies – How to Write Testable Code? sloooowwww sfContext, Database, ... Test Tested Class Dependency
How to Replace Slow Dependencies?
Fake Objects
Testing Strategies – How to Write Testable Code? Test Tested Class Fake Object
Testing Strategies – Slow Dependencies class  CukeetRecipe { public   function  save(CukeetCategoryTable  $categoryTable ) { if  (is_null( $this ->Category)) { $this ->Category =  $categoryTable ->findDefault(); } } }
Testing Strategies – Fake Objects // @Test: The default category is assigned, if empty // setup $defaultCategory  =  new  CukeetCategory(); $categoryTable  =  new  FakeCategoryTable( $defaultCategory ); // test $recipe  =  new  CukeetRecipe(); $recipe ->Category =  null ; $recipe ->save( $categoryTable ); // assertions $t ->is( $recipe ->Category,  $defaultCategory ,  'The default...' );
Testing Strategies – Fake Objects class  FakeCategoryTable  extends  CukeetCategoryTable { protected   $defaultCategory ; public   function  __construct(CukeetCategory  $defaultCategory ) { $this ->defaultCategory =  $defaultCategory ; } public   function  findDefault() { return   $this ->defaultCategory; } }
Testing Strategies – Stub Objects ,[object Object]
Acts „as if“ it was the real object
Does not have any logic inside
Testing Strategies – Stub Objects // @Test: The default category is assigned, if empty // setup $defaultCategory  =  new  CukeetCategory(); $categoryTable  =  $t ->stub( 'CukeetCategoryTable' ); $categoryTable ->findDefault()->returns( $defaultCategory ); $categoryTable ->replay(); // test $recipe  =  new  CukeetRecipe(); $recipe ->Category =  null ; $recipe ->save( $categoryTable ); // assertions $t ->is( $recipe ->Category,  $defaultCategory ,  'The default...' ); Stub Generation in Lime 2
Testing Strategies – Stub Objects // @Test: The default category is assigned, if empty // setup $defaultCategory  =  new  CukeetCategory(); $categoryTable  =  $t ->stub( 'CukeetCategoryTable' ); $categoryTable ->findDefault()->returns( $defaultCategory ); $categoryTable ->replay(); // test $recipe  =  new  CukeetRecipe(); $recipe ->Category =  null ; $recipe ->save( $categoryTable ); // assertions $t ->is( $recipe ->Category,  $defaultCategory ,  'The default...' ); Stub Configuration
Testing Strategies – Stub Objects ,[object Object]
Replace services (table, ...)
Testing Strategies – Stub Objects Test  state after  test execution Test Tested Class Stub
Testing Strategies – Mock Objects Test  behaviour during  test execution Test Tested Class Mock
Testing Strategies – Mock Objects ,[object Object]
Monitors indirect input
Does the tested object call the right methods?
Testing Strategies – Mock Objects // @Test: Upon destruction all data is saved to the session // setup $storage  =  $t ->mock( 'CukeetSessionStorage' ); $storage ->write( 'Foo' ,  'Bar' ); $storage ->replay(); $user  =  new  CukeetUser( $storage ); // test $user ->setAttribute( 'Foo' ,  'Bar' ); $user ->__destruct(); // assertions $storage ->verify();
Testing Strategies – Mock Objects ,[object Object]

More Related Content

What's hot

Curso Symfony - Clase 2
Curso Symfony - Clase 2Curso Symfony - Clase 2
Curso Symfony - Clase 2Javier Eguiluz
 
Rich Snippets in Magento product page
Rich Snippets in Magento product pageRich Snippets in Magento product page
Rich Snippets in Magento product pageHans Kuijpers
 
4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
4Developers 2015: Be pragmatic, be SOLID - Krzysztof MenżykPROIDEA
 
Rich Snippets in Magento product page - #MUG020
Rich Snippets in Magento product page - #MUG020Rich Snippets in Magento product page - #MUG020
Rich Snippets in Magento product page - #MUG020Hans Kuijpers
 
Using of TDD practices for Magento
Using of TDD practices for MagentoUsing of TDD practices for Magento
Using of TDD practices for MagentoIvan Chepurnyi
 
PHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsPHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsMichelangelo van Dam
 
Zf2 how arrays will save your project
Zf2   how arrays will save your projectZf2   how arrays will save your project
Zf2 how arrays will save your projectMichelangelo van Dam
 
Fixing Magento Core for Better Performance - Ivan Chepurnyi
Fixing Magento Core for Better Performance - Ivan ChepurnyiFixing Magento Core for Better Performance - Ivan Chepurnyi
Fixing Magento Core for Better Performance - Ivan ChepurnyiMeet Magento Spain
 
Тестирование и Django
Тестирование и DjangoТестирование и Django
Тестирование и DjangoMoscowDjango
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using CodeceptionJeroen van Dijk
 
SugarCon 2010 - Best Practices for Creating Custom Apps in Sugar
SugarCon 2010 - Best Practices for Creating Custom Apps in SugarSugarCon 2010 - Best Practices for Creating Custom Apps in Sugar
SugarCon 2010 - Best Practices for Creating Custom Apps in SugarJohn Mertic
 
PHPunit and you
PHPunit and youPHPunit and you
PHPunit and youmarkstory
 
Best practices for js testing
Best practices for js testingBest practices for js testing
Best practices for js testingKarl Mendes
 
Сергей Иващенко - Meet Magento Ukraine - Цены в Magento 2
Сергей Иващенко - Meet Magento Ukraine - Цены в Magento 2Сергей Иващенко - Meet Magento Ukraine - Цены в Magento 2
Сергей Иващенко - Meet Magento Ukraine - Цены в Magento 2Atwix
 

What's hot (20)

Curso Symfony - Clase 2
Curso Symfony - Clase 2Curso Symfony - Clase 2
Curso Symfony - Clase 2
 
QA for PHP projects
QA for PHP projectsQA for PHP projects
QA for PHP projects
 
Rich Snippets in Magento product page
Rich Snippets in Magento product pageRich Snippets in Magento product page
Rich Snippets in Magento product page
 
4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
 
Rich Snippets in Magento product page - #MUG020
Rich Snippets in Magento product page - #MUG020Rich Snippets in Magento product page - #MUG020
Rich Snippets in Magento product page - #MUG020
 
Images and PWA in magento
Images and PWA in magentoImages and PWA in magento
Images and PWA in magento
 
Using of TDD practices for Magento
Using of TDD practices for MagentoUsing of TDD practices for Magento
Using of TDD practices for Magento
 
Backbone - TDC 2011 Floripa
Backbone - TDC 2011 FloripaBackbone - TDC 2011 Floripa
Backbone - TDC 2011 Floripa
 
PHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsPHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the tests
 
Zf2 how arrays will save your project
Zf2   how arrays will save your projectZf2   how arrays will save your project
Zf2 how arrays will save your project
 
Fixing Magento Core for Better Performance - Ivan Chepurnyi
Fixing Magento Core for Better Performance - Ivan ChepurnyiFixing Magento Core for Better Performance - Ivan Chepurnyi
Fixing Magento Core for Better Performance - Ivan Chepurnyi
 
Factory Girl
Factory GirlFactory Girl
Factory Girl
 
Тестирование и Django
Тестирование и DjangoТестирование и Django
Тестирование и Django
 
Recettes de tests
Recettes de testsRecettes de tests
Recettes de tests
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
 
SugarCon 2010 - Best Practices for Creating Custom Apps in Sugar
SugarCon 2010 - Best Practices for Creating Custom Apps in SugarSugarCon 2010 - Best Practices for Creating Custom Apps in Sugar
SugarCon 2010 - Best Practices for Creating Custom Apps in Sugar
 
PHPunit and you
PHPunit and youPHPunit and you
PHPunit and you
 
WCLV13 JavaScript
WCLV13 JavaScriptWCLV13 JavaScript
WCLV13 JavaScript
 
Best practices for js testing
Best practices for js testingBest practices for js testing
Best practices for js testing
 
Сергей Иващенко - Meet Magento Ukraine - Цены в Magento 2
Сергей Иващенко - Meet Magento Ukraine - Цены в Magento 2Сергей Иващенко - Meet Magento Ukraine - Цены в Magento 2
Сергей Иващенко - Meet Magento Ukraine - Цены в Magento 2
 

Similar to Best Practice Testing with Lime 2

Testing persistence in PHP with DbUnit
Testing persistence in PHP with DbUnitTesting persistence in PHP with DbUnit
Testing persistence in PHP with DbUnitPeter Wilcsinszky
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxMichelangelo van Dam
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
Advanced PHPUnit Testing
Advanced PHPUnit TestingAdvanced PHPUnit Testing
Advanced PHPUnit TestingMike Lively
 
Quality Use Of Plugin
Quality Use Of PluginQuality Use Of Plugin
Quality Use Of PluginYasuo Harada
 
From typing the test to testing the type
From typing the test to testing the typeFrom typing the test to testing the type
From typing the test to testing the typeWim Godden
 
Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013Michelangelo van Dam
 
Workshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastWorkshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastMichelangelo van Dam
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Michelangelo van Dam
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)arcware
 
Test in action week 4
Test in action   week 4Test in action   week 4
Test in action week 4Yi-Huan Chan
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosDivante
 
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur PurnamaEPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur PurnamaEnterprise PHP Center
 
Creating and Maintaining WordPress Plugins
Creating and Maintaining WordPress PluginsCreating and Maintaining WordPress Plugins
Creating and Maintaining WordPress PluginsMark Jaquith
 

Similar to Best Practice Testing with Lime 2 (20)

PHP Unit Testing
PHP Unit TestingPHP Unit Testing
PHP Unit Testing
 
Testing persistence in PHP with DbUnit
Testing persistence in PHP with DbUnitTesting persistence in PHP with DbUnit
Testing persistence in PHP with DbUnit
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
Test driven development_for_php
Test driven development_for_phpTest driven development_for_php
Test driven development_for_php
 
Advanced PHPUnit Testing
Advanced PHPUnit TestingAdvanced PHPUnit Testing
Advanced PHPUnit Testing
 
Quality Use Of Plugin
Quality Use Of PluginQuality Use Of Plugin
Quality Use Of Plugin
 
PHPUnit testing to Zend_Test
PHPUnit testing to Zend_TestPHPUnit testing to Zend_Test
PHPUnit testing to Zend_Test
 
From typing the test to testing the type
From typing the test to testing the typeFrom typing the test to testing the type
From typing the test to testing the type
 
Be pragmatic, be SOLID
Be pragmatic, be SOLIDBe pragmatic, be SOLID
Be pragmatic, be SOLID
 
Clean tests good tests
Clean tests   good testsClean tests   good tests
Clean tests good tests
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013
 
Workshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastWorkshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfast
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
 
Test in action week 4
Test in action   week 4Test in action   week 4
Test in action week 4
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
 
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur PurnamaEPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
 
Creating and Maintaining WordPress Plugins
Creating and Maintaining WordPress PluginsCreating and Maintaining WordPress Plugins
Creating and Maintaining WordPress Plugins
 

Recently uploaded

"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentationphoebematthew05
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 

Recently uploaded (20)

"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentation
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 

Best Practice Testing with Lime 2

  • 1. Best Practice Testing with Lime 2 Bernhard Schussek
  • 2.
  • 3.
  • 4. Search Engine Marketing & Optimization
  • 5.
  • 7. Part I The Interactive Stuff
  • 8. What is important? Brainstorming
  • 9.
  • 10.
  • 12.
  • 15.
  • 18.
  • 19.
  • 22.
  • 23. Part II Testing Strategies
  • 27. How to Write Testable Code?
  • 30. Creation and Helper Functions
  • 32.
  • 35. ...
  • 36. Testing Strategies – 4 Phase Test // @Test: resize() resizes the thumbnail copy( 'data/fixtures/test.png' , 'web/uploads/test.png' ); $thumbnail = new CukeetThumbnail( 'web/uploads/test.png' ); $thumbnail ->resize( 100 , 100 ); $size = getimagesize( $thumbnail ->getPath()); $t ->is( $size , array ( 100 , 100 ), 'The image has been resized' ); unlink( 'web/uploads/test.png' ); unset( $thumbnail ); Our Tested Class
  • 37. Testing Strategies – 4 Phase Test // @Test: resize() resizes the thumbnail copy( 'data/fixtures/test.png' , 'web/uploads/test.png' ); $thumbnail = new CukeetThumbnail( 'web/uploads/test.png' ); $thumbnail ->resize( 100 , 100 ); $size = getimagesize( $thumbnail ->getPath()); $t ->is( $size , array ( 100 , 100 ), 'The image has been resized' ); unlink( 'web/uploads/test.png' ); unset( $thumbnail ); Fixture Setup
  • 38. Testing Strategies – 4 Phase Test // @Test: resize() resizes the thumbnail copy( 'data/fixtures/test.png' , 'web/uploads/test.png' ); $thumbnail = new CukeetThumbnail( 'web/uploads/test.png' ); $thumbnail ->resize( 100 , 100 ); $size = getimagesize( $thumbnail ->getPath()); $t ->is( $size , array ( 100 , 100 ), 'The image has been resized' ); unlink( 'web/uploads/test.png' ); unset( $thumbnail ); Test Execution
  • 39. Testing Strategies – 4 Phase Test // @Test: resize() resizes the thumbnail copy( 'data/fixtures/test.png' , 'web/uploads/test.png' ); $thumbnail = new CukeetThumbnail( 'web/uploads/test.png' ); $thumbnail ->resize( 100 , 100 ); $size = getimagesize( $thumbnail ->getPath()); $t ->is( $size , array ( 100 , 100 ), 'The image has been resized' ); unlink( 'web/uploads/test.png' ); unset( $thumbnail ); Result Verification
  • 40. Testing Strategies – 4 Phase Test // @Test: resize() resizes the thumbnail copy( 'data/fixtures/test.png' , 'web/uploads/test.png' ); $thumbnail = new CukeetThumbnail( 'web/uploads/test.png' ); $thumbnail ->resize( 100 , 100 ); $size = getimagesize( $thumbnail ->getPath()); $t ->is( $size , array ( 100 , 100 ), 'The image has been resized' ); unlink( 'web/uploads/test.png' ); unset( $thumbnail ); Fixture Teardown
  • 41.
  • 44.
  • 45. Make it obvious what you are testing
  • 46. Testing Strategies – 4 Phase Test // @Test: resize() resizes the thumbnail // setup copy( 'data/fixtures/test.png' , 'web/uploads/test.png' ); // test $thumbnail = new CukeetThumbnail( 'web/uploads/test.png' ); $thumbnail ->resize( 100 , 100 ); // assertions $size = getimagesize( $thumbnail ->getPath()); $t ->is( $size , array ( 100 , 100 ), 'The image has been resized' ); // teardown unlink( 'web/uploads/test.png' ); unset( $thumbnail ); Use Comments!
  • 48.
  • 50. Testing Strategies – The Test Fixture Global Fixture Fresh Fixture Fixture Setup test.png, new CukeetThumbnail() Test 1 Test 2 Test 3 Test 4 Fixture Setup test.png, new CukeetThumbnail() Test 1 Test 2 Fixture Setup test.png, new CukeetThumbnail() Fixture Setup
  • 53.
  • 57. Testing Strategies – Annotations // @Before copy( 'data/fixtures/test.png' , 'web/uploads/test.png' ); $thumbnail = new CukeetThumbnail( 'web/uploads/test.png' ); // @After unlink( 'web/uploads/test.png' ); unset( $thumbnail ); // @Test: resize() resizes the thumbnail $thumbnail ->resize( 100 , 100 ); $size = getimagesize( $thumbnail ->getPath()); $t ->is( $size , array ( 100 , 100 ), 'The image has been resized' );
  • 58.
  • 59. Fixtures can be built and destroyed automatically
  • 60. The chance of interacting tests is reduced
  • 61. Testing Strategies – xUnit Style Test Class class CukeetThumbnailTest extends LimeTestCase { private $thumbnail ; public function setup() { copy( 'data/fixtures/test.png' , 'web/uploads/test.png' ); $this ->thumbnail = new CukeetThumbnail( 'web/uploads/test.png' ); } public function teardown() { unlink( 'web/uploads/test.png' ); unset( $this ->thumbnail); } public function testTheThumbnailCanBeResized() {} } Same As With Annotations
  • 62. How to Write Testable Code?
  • 63. Testing Strategies – How to Write Testable Code class CukeetRecipe { public function save() { $user = sfContext::getInstance()->getUser(); if (! $user ->hasCredential( 'admin' )) { throw new RuntimeException( 'No permission!' ); } } }
  • 64. Testing Strategies – How to Write Testable Code class CukeetRecipe { public function save() { $user = sfContext::getInstance()->getUser(); if (! $user ->hasCredential( 'admin' )) { throw new RuntimeException( 'No permission!' ); } } } Uh oh...
  • 68. Testing Strategies – How to Write Testable Code? ? Test Tested Class Dependency
  • 70.
  • 71. Testing Strategies – Constructor Injection class CukeetRecipe { private $user ; public function __construct(sfBasicSecurityUser $user ) { $this ->user = $user ; } public function save() { if (! $this ->user->hasCredential( 'admin' )) { throw new RuntimeException( 'No permission!' ); } }
  • 72. Testing Strategies – Dependency Injection // @Before $user = new sfBasicSecurityUser(); $recipe = new CukeetRecipe( $user ); // @Test: Users with credential 'admin' can save $user ->addCredential( 'admin' ); $recipe ->save( $user ); // @Test: Normal users cannot save $t ->expect( 'RuntimeException' ); $recipe ->save( $user );
  • 73. Testing Strategies – How to Write Testable Code? Test Tested Class Dependency
  • 74. Testing Strategies – How to Write Testable Code? sloooowwww sfContext, Database, ... Test Tested Class Dependency
  • 75. How to Replace Slow Dependencies?
  • 77. Testing Strategies – How to Write Testable Code? Test Tested Class Fake Object
  • 78. Testing Strategies – Slow Dependencies class CukeetRecipe { public function save(CukeetCategoryTable $categoryTable ) { if (is_null( $this ->Category)) { $this ->Category = $categoryTable ->findDefault(); } } }
  • 79. Testing Strategies – Fake Objects // @Test: The default category is assigned, if empty // setup $defaultCategory = new CukeetCategory(); $categoryTable = new FakeCategoryTable( $defaultCategory ); // test $recipe = new CukeetRecipe(); $recipe ->Category = null ; $recipe ->save( $categoryTable ); // assertions $t ->is( $recipe ->Category, $defaultCategory , 'The default...' );
  • 80. Testing Strategies – Fake Objects class FakeCategoryTable extends CukeetCategoryTable { protected $defaultCategory ; public function __construct(CukeetCategory $defaultCategory ) { $this ->defaultCategory = $defaultCategory ; } public function findDefault() { return $this ->defaultCategory; } }
  • 81.
  • 82. Acts „as if“ it was the real object
  • 83. Does not have any logic inside
  • 84. Testing Strategies – Stub Objects // @Test: The default category is assigned, if empty // setup $defaultCategory = new CukeetCategory(); $categoryTable = $t ->stub( 'CukeetCategoryTable' ); $categoryTable ->findDefault()->returns( $defaultCategory ); $categoryTable ->replay(); // test $recipe = new CukeetRecipe(); $recipe ->Category = null ; $recipe ->save( $categoryTable ); // assertions $t ->is( $recipe ->Category, $defaultCategory , 'The default...' ); Stub Generation in Lime 2
  • 85. Testing Strategies – Stub Objects // @Test: The default category is assigned, if empty // setup $defaultCategory = new CukeetCategory(); $categoryTable = $t ->stub( 'CukeetCategoryTable' ); $categoryTable ->findDefault()->returns( $defaultCategory ); $categoryTable ->replay(); // test $recipe = new CukeetRecipe(); $recipe ->Category = null ; $recipe ->save( $categoryTable ); // assertions $t ->is( $recipe ->Category, $defaultCategory , 'The default...' ); Stub Configuration
  • 86.
  • 88. Testing Strategies – Stub Objects Test state after test execution Test Tested Class Stub
  • 89. Testing Strategies – Mock Objects Test behaviour during test execution Test Tested Class Mock
  • 90.
  • 92. Does the tested object call the right methods?
  • 93. Testing Strategies – Mock Objects // @Test: Upon destruction all data is saved to the session // setup $storage = $t ->mock( 'CukeetSessionStorage' ); $storage ->write( 'Foo' , 'Bar' ); $storage ->replay(); $user = new CukeetUser( $storage ); // test $user ->setAttribute( 'Foo' , 'Bar' ); $user ->__destruct(); // assertions $storage ->verify();
  • 94.
  • 96. Overuse of mocks can harm your health
  • 97. Testing Strategies – Functional Tests $browser ->info( '1 - Recipes are displayed in each category' ) ->info( ' 1.1 - The two most recent recipes are displayed' ) ->click( 'Desserts' ) ->with( 'response' )->begin() ->checkElement( '#recipes li:first' , '/Deluxe Apples/' ) ->checkElement( '#recipes li:last' , '/Quatre Quarts/' ) ->checkElement( '#recipes li' , 2 ) ->end() ->click( 'Burgers' ) ->with( 'response' )->begin() ->checkElement( '#recipes li:first' , '/Kamikaze Burgers/' ) ->checkElement( '#recipes li:last' , '/Surprise Burgers/' ) ->checkElement( '#recipes li' , 2 ) ->end()
  • 99.
  • 100. Test the system as a whole
  • 102.
  • 104.
  • 106.
  • 107. Testing Strategies – Functional vs. Unit Tests $browser ->info( '1 - Recipes are displayed in each category' ) ->info( ' 1.1 - The two most recent recipes are displayed' ) ->click( 'Desserts' ) ->with( 'response' )->begin() ->checkElement( '#recipes li:first' , '/Deluxe Apples/' ) ->checkElement( '#recipes li:last' , '/Quatre Quarts/' ) ->checkElement( '#recipes li' , 2 ) ->end() ->click( 'Burgers' ) ->with( 'response' )->begin() ->checkElement( '#recipes li:first' , '/Kamikaze Burgers/' ) ->checkElement( '#recipes li:last' , '/Surprise Burgers/' ) ->checkElement( '#recipes li' , 2 ) ->end()
  • 108. Testing Strategies – Test Edge Cases in Unit Tests // CukeetRecipeTableTest.php require_once dirname(__FILE__). '/../bootstrap/doctrine.php' ; $t ->comment( 'findRecent() returns recent recipes of a category' ); // setup ... // test $actual = $table ->findRecent( 2 , $category ); // assertions ... $t ->is( $actual , $expected , 'The correct recipes were returned' );
  • 109. Testing Strategies – Test Edge Cases in Unit Tests // CukeetRecipeTableTest.php require_once dirname(__FILE__). '/../bootstrap/doctrine.php' ; $t ->comment( 'findRecent() returns recent recipes of a category' ); // setup ... // test $actual = $table ->findRecent( 2 , $category ); // assertions ... $t ->is( $actual , $expected , 'The correct recipes were returned' ); Bootstrap File
  • 110. Testing Strategies – Test Edge Cases in Unit Tests // bootstrap/doctrine.php require_once dirname(__FILE__). '/unit.php' ; $database = new sfDoctrineDatabase( array ( 'name' => 'doctrine' , 'dsn' => 'sqlite::memory:' , )); // load missing model files and create tables Doctrine::createTablesFromModels(ROOT_DIR. '/lib/model' ); // load fixture data Doctrine::loadData( 'data/fixtures/fixtures.yml' ); Load YAML Fixtures
  • 111. Testing Strategies – The Test Fixture Global Fixture Fixture Setup test.png, new CukeetThumbnail() Test 1 Test 2 Test 3 Test 4
  • 112. Testing Strategies – Use Inline Fixtures // @Before reload(); $table = Doctrine::getTable( 'CukeetRecipe' ); // @Test: findRecent() returns recent recipes of a category // setup $category = new CukeetCategory(); $category ->fromArray( array ( 'name' => 'Desserts' , ...)); $recipe1 = new CukeetRecipe(); $recipe1 ->fromArray( array ( 'name' => 'Quatre Quarts' , ...)); $recipe1 ->Category = $category ; $recipe1 ->save(); ...
  • 113. Creation and Helper Functions
  • 114. Testing Strategies – Creation and Helper Functions // @Test: findRecent() returns recent recipes of a category // setup $category = createCategory(); $recipe1 = createRecipeInCategory( $category ); $recipe2 = createRecipeInCategory( $category ); $recipe3 = createRecipe(); $recipe4 = createRecipeInCategory( $category ); save( $recipe1 , $recipe2 , $recipe3 , $recipe4 ); // test $actual = $table ->findRecent( 2 , $category ); // assertions $expected = createCollection( $recipe4 , $recipe2 ); $t ->is( $actual , $expected , 'The correct recipes were returned' );
  • 115. Testing Strategies – Creation and Helper Functions // bootstrap/doctrine.php function createRecipe( array $properties = array ()) { static $i = 0 ; $recipe = new CukeetRecipe(); $recipe ->fromArray(array_merge( array ( 'name' => 'Recipe ' . ++ $i , 'created_at' => date( 'Y-m-d H:m:i' , $i ), ), $properties )); return $recipe ; }
  • 116. Testing Strategies – Functional Test Revisited (1) $browser ->info( '1 - Recipes are displayed in each category' ) ->info( ' 1.1 - The two most recent recipes are displayed' ) ->click( 'Desserts' ) ->with( 'response' )->begin() ->checkElement( '#recipes li:first' , '/Deluxe Apples/' ) ->checkElement( '#recipes li:last' , '/Quatre Quarts/' ) ->checkElement( '#recipes li' , 2 ) ->end() ->click( 'Burgers' ) ->with( 'response' )->begin() ->checkElement( '#recipes li:first' , '/Kamikaze Burgers/' ) ->checkElement( '#recipes li:last' , '/Surprise Burgers/' ) ->checkElement( '#recipes li' , 2 ) ->end( )
  • 117. Testing Strategies – Functional Test Revisited (2) $browser ->info( '1 - Recipes are displayed in each category' ) ->info( ' 1.1 - The two most recent recipes are displayed' ) ->click( 'Desserts' ) ->with( 'response' )->begin() ->checkElement( '#recipes li:first' , '/Deluxe Apples/' ) ->checkElement( '#recipes li:last' , '/Quatre Quarts/' ) ->checkElement( '#recipes li' , 2 ) ->end() ->click( 'Burgers' ) ->with( 'response' )->begin() ->checkElement( '#recipes li:first' , '/Kamikaze Burgers/' ) ->checkElement( '#recipes li:last' , '/Surprise Burgers/' ) ->checkElement( '#recipes li' , 2 ) ->end()
  • 119.
  • 123. Stubs
  • 124. Mocks
  • 126. Creation and Helper Functions
  • 127. Part III Whatz Nu in Lime 2
  • 129. What Nu in Lime 2 – Annotation Support // @Before copy( 'data/fixtures/test.png' , 'web/uploads/test.png' ); $thumbnail = new CukeetThumbnail( 'web/uploads/test.png' ); // @After unlink( 'web/uploads/test.png' ); unset( $thumbnail ); // @Test: resize() resizes the thumbnail $thumbnail ->resize( 100 , 100 ); $size = getimagesize( $thumbnail ->getPath()); $t ->is( $size , array ( 100 , 100 ), 'The image has been resized' );
  • 130. Stub & Mock Generation
  • 131. Whatz Nu in Lime 2 – Mock Objects // @Test: Upon destruction all data is saved to the session // setup $storage = $t ->mock( 'SessionStorage' ); $storage ->write( 'Foo' , 'Bar' )->returns( true )->once(); $storage ->flush()->atLeastOnce(); $storage ->any( 'read' )->throws( 'BadMethodCallException' ); $storage ->replay(); // test ...
  • 133. What Nu in Lime 2 – Improved Error Messages # got: object(CukeetRecipe) ( # ... # '_data' => array ( # ... # 'name' => 'Quatre Quarts', # ... # ), # ) # expected: object(CukeetRecipe) ( # ... # '_data' => array ( # ... # 'name' => 'Kamikaze Burger', # ... # ), # )
  • 135.
  • 136. One CPU core at 100%
  • 137.
  • 138.
  • 140.
  • 141.
  • 144. ...
  • 145. Integration With CI-Tools sismo php Under Control
  • 146. ?