finding the right testing tool for the job
TRANSCRIPT
![Page 1: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/1.jpg)
Finding the Right Testing Tool for the Job
Sebastian Bergmann and Ciaran McNulty
![Page 2: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/2.jpg)
Who are these guys?
![Page 3: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/3.jpg)
3 Dimensions of Testing
Goal - why we are writing the testScope - how much of the system is involved in the testForm - how we express the test
![Page 4: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/4.jpg)
![Page 5: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/5.jpg)
3 4 Dimensions of Testing
Goal - why we are writing the testScope - how much of the system is involved in the testForm - how we express the testTime - when we write the test
![Page 6: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/6.jpg)
What we will talk about
— Characterisation Tests
— Acceptance Tests
— Integration Tests
— Unit Tests
![Page 7: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/7.jpg)
Characterisation Tests
![Page 8: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/8.jpg)
Characterisation TestsGoals:
— Capture existing behaviour
— Find out when behaviour changes
![Page 9: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/9.jpg)
Characterisation TestsScopes:
— Often at UI level
— Sometimes at object/service level
![Page 10: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/10.jpg)
Characterisation TestsTimes:
— Always after implementation
![Page 11: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/11.jpg)
Characterisation TestsBest practice:
— Treat these tests as a temporary measure
— Use a tool that makes it easy to create tests
— Expect pain and suffering
![Page 12: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/12.jpg)
Characterisation TestsForm: Behat + MinkExtension builtin steps
Scenario: Product search returns results Given I am on "/" And I fill in "search" with "Blue jeans" When I press "go" Then I should see "100 Results Found"
![Page 13: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/13.jpg)
Characterisation TestsForm: PHPUnit + phpunit-mink-trait
class SearchTest extends PHPUnit_Framework_TestCase{ use phpunit\mink\TestCaseTrait;
public function testProductSearchReturnsResult() { $page = $this->visit('http://example.com/');
$page->fillField('search', 'Blue Jeans'); $page->pressButton('go');
$this->assertContains('100 Results Found', $page->getText()); }}
![Page 14: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/14.jpg)
Characterisation TestsForm: Selenium IDE
![Page 15: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/15.jpg)
Characterisation TestsForm: Ghost Inspector
![Page 16: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/16.jpg)
Characterisation TestsForm: PHPUnit + de-legacy-fy
See docs at on GitHub at sebastianbergmann/de-legacy-fy
![Page 17: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/17.jpg)
Acceptance Tests
![Page 18: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/18.jpg)
Acceptance TestsGoals:
— Match system behaviour to business requirements
— Get feedback on proposed implementations
— Understand business better
— Document behaviour for the future
![Page 19: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/19.jpg)
Acceptance TestsScopes:
— At a UI layer
— At an API layer
— At the service layer
— Lower level may be too disconnected
![Page 20: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/20.jpg)
Acceptance TestsTimes:
— Before implementation
— Before commitment (as long as it's not expensive?)
— Hard to write in retrospect
![Page 21: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/21.jpg)
Acceptance TestsBest practices:
— Get feedback on tests early
— Make them readable, or have readable output, for the intended audience
— Apply for the smallest scope first
— Apply to core domain model first
— Minimise end-to-end tests
![Page 22: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/22.jpg)
Acceptance TestsForm: Behat at service level
Scenario: Sales tax is applied to basket Given "Blue Jeans" are priced as €100 in the catalogue When I add "Blue Jeans" to my shopping basket Then the basket total should be €120
![Page 23: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/23.jpg)
class BasketContext implements Context{ public function __construct() { $this->catalogue = new InMemory\Catalogue(); $this->basket = new Basket($catalogue); }
/** * @Given :productName is/are priced as :cost in the catalogue */ public function priceProduct(ProductName $productName, Cost $cost) { $this->catalogue->price($productName, $cost); } //...}
![Page 24: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/24.jpg)
class BasketContext implements Context{ //... /** * @When I add :productName to my shopping basket */ public function addProductToBasket(ProductName $productName) { $this->basket->add($productName); }
/** * @Then the basket total should be :cost */ public function checkBasketTotal(Cost $cost) { assert($this->basket->total == $cost->asInt()); }}
![Page 25: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/25.jpg)
Acceptance TestsForm: PHPUnit at service level
class BasketTest extends PHPUnit_Framework_TestCase{ public function testSalesTaxIsApplied() { $catalogue = new InMemory\Catalogue(); $basket = new Basket($catalogue);
$productName = new ProductName('Blue Jeans'); $catalogue->price($productName, new Cost('100')); $basket->add($productName);
$this->assertEquals(new Cost('120'), $basket->calculateTotal()); }}
![Page 26: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/26.jpg)
Acceptance TestsForm: PHPUnit at service level
![Page 27: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/27.jpg)
Acceptance TestsForm: Behat at UI level
Scenario: Sales tax is applied to basket Given "Blue Jeans" are priced as €100 in the catalogue When I add "Blue Jeans" to my shopping basket Then the basket total should be €120
![Page 28: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/28.jpg)
class BasketUiContext extends MinkContext{ public function __construct() { $this->catalogue = new Catalogue(/* ... */); }
/** * @Given :productName is/are priced as :cost in the catalogue */ public function priceProduct(ProductName $productName, Cost $cost) { $this->catalogue->price($productName, $cost); } //...}
![Page 29: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/29.jpg)
class BasketUiContext extends MinkContext{ //... /** * @When I add :productName to my shopping basket */ public function addProductToBasket(ProductName $productName) { $this->visitPath('/products/'.urlencode($productName)); $this->getSession()->getPage()->pressButton('Add to Basket'); }
/** * @Then the basket total should be :cost */ public function checkBasketTotal(Cost $cost) { $this->assertElementContains('#basket .total', '€120'); }}
![Page 30: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/30.jpg)
Acceptance TestsForm: PHPUnit at UI level
class BasketUiTest extends PHPUnit_Framework_TestCase{ use phpunit\mink\TestCaseTrait;
public function testSalesTaxIsApplied() { $catalogue = new Catalogue(/* ... */); $catalogue->price(new ProductName('Blue Jeans'), new Cost(120));
$page = $this->visit('http://example.com/products/'.urlencode($productName)); $this->getSession()->getPage()->pressButton('Add to Basket');
$this->assertContains( '€120', $page->find('css', '#basket .total')->getText() ); }}
![Page 31: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/31.jpg)
Integration Tests
![Page 32: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/32.jpg)
Integration TestsGoals:
— Test cross-boundary communication
— Test integration with concrete infrastructure
![Page 33: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/33.jpg)
Integration TestsScopes:
— Large parts of the system
— Focus on the edges (not core domain)
— Areas where your code interacts with third-party code
![Page 34: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/34.jpg)
Integration TestsTimes:
— After the feature is implemented in core / contracts are established
— During integration with real infrastructure
— When you want to get more confidence in integration
— When cases are not covered by End-to-End acceptance test
![Page 35: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/35.jpg)
Integration TestsBest Practices:
— Use tools with existing convenient integrations
— Focus on testing through your API
— Make sure your core domain has an interface
![Page 36: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/36.jpg)
Integration TestsForm: PHPUnit + DbUnit
class CatalogueTest extends PHPUnit_Extensions_Database_TestCase{ public function getConnection() { $pdo = new PDO(/* ... */); return $this->createDefaultDBConnection($pdo, 'myDatabase'); }
public function getDataSet() { return $this->createFlatXMLDataSet(dirname(__FILE__) . '/_files/catalogue-seed.xml'); } // ...}
![Page 37: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/37.jpg)
class CatalogueTest extends PHPUnit_Extensions_Database_TestCase{ // ...
public function testProductCanBePriced() { $catalogue = new Catalogue(/* ... */);
$catalogue->price( new ProductName('Blue Jeans'), new Cost('100') );
$this->assertEquals( new Cost('100'), $catalogue->lookUp(new ProductName('Blue Jeans') ); }}
![Page 38: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/38.jpg)
Unit Tests
![Page 39: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/39.jpg)
Unit TestsGoals:
— Test components individually
— Catch errors earlier
— Drive internal design quality
— Document units for other developers
![Page 40: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/40.jpg)
Unit Tests:Scopes:
— Single classes
— Single classes + value objects?
— Extremely small units of code
![Page 41: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/41.jpg)
Unit Tests:Times:
— Just before you implement
![Page 42: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/42.jpg)
Unit Tests:Times:
— Just before you implement
OK, maybe...
— Just after you implement
— If you want to learn more about a class
— But always before you share the code!
![Page 43: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/43.jpg)
Unit TestsBest Practices
— Write in a descriptive style
— Describe interactions using Test Doubles
— Don't get too hung up on isolation
— Don't touch infrastructure
— Don't test other people's code
— Don't double other people's code?
![Page 44: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/44.jpg)
Unit TestsForm: PHPUnit
class BasketTest extends PHPUnit_Framework_TestCase{ public function testSalesTaxIsApplied() { $catalogue = $this->getMock(Catalogue::class); $catalogue->method('lookUp')->with(new ProductName('Blue Jeans')) ->willReturn(new Cost('100'));
$basket = new Basket($catalogue); $basket->add(new ProductName('Blue Jeans'));
$this->assertSame(new Cost('120'), $basket->calculateTotal()); }
}
![Page 45: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/45.jpg)
Unit TestsForm: PhpSpec
class BasketSpec extends ObjectBehavior{ function it_applies_sales_tax(Catalogue $catalogue) { $catalogue->lookUp(new ProductName('Blue Jeans'))->willReturn(new Cost('100')); $this->beConstructedWith($catalogue);
$this->add(new ProductName('Blue Jeans'));
$basket->calculateTotal()->shouldBeLike(new Cost('120')); }
}
![Page 46: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/46.jpg)
5th Dimension - Who?
— Choose the right approaches for your context
— What mix of languages can the team use?
— What styles of testing will add the most value?
— What formats make the most sense to the team?
— How will tests fit into the development process?
There is no right answer, there are many right answers!
![Page 47: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/47.jpg)
Photo Credits
— "tools" by velacreations (CC) - https://flic.kr/p/8ZSb3r
— "Components" by Jeff Keyzer (CC) - https://flic.kr/p/4ZNZp1
— Doctor Who stolen from BBC.co.uk
— Other images used under license
![Page 48: Finding the Right Testing Tool for the Job](https://reader033.vdocument.in/reader033/viewer/2022042907/587f3d2e1a28ab43318b4f41/html5/thumbnails/48.jpg)
Thank You & Questions?
@s_bergmann@ciaranmcnulty
https://joind.in/talk/80dbd