finding the right testing tool for the job

48
Finding the Right Testing Tool for the Job Sebastian Bergmann and Ciaran McNulty

Upload: ciaranmcnulty

Post on 18-Jan-2017

288 views

Category:

Software


3 download

TRANSCRIPT

Page 1: Finding the Right Testing Tool for the Job

Finding the Right Testing Tool for the Job

Sebastian Bergmann and Ciaran McNulty

Page 2: Finding the Right Testing Tool for the Job

Who are these guys?

Page 3: Finding the Right Testing Tool for the Job

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
Page 5: Finding the Right Testing Tool for the Job

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

What we will talk about

— Characterisation Tests

— Acceptance Tests

— Integration Tests

— Unit Tests

Page 7: Finding the Right Testing Tool for the Job

Characterisation Tests

Page 8: Finding the Right Testing Tool for the Job

Characterisation TestsGoals:

— Capture existing behaviour

— Find out when behaviour changes

Page 9: Finding the Right Testing Tool for the Job

Characterisation TestsScopes:

— Often at UI level

— Sometimes at object/service level

Page 10: Finding the Right Testing Tool for the Job

Characterisation TestsTimes:

— Always after implementation

Page 11: Finding the Right Testing Tool for the Job

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

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

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

Characterisation TestsForm: Selenium IDE

Page 15: Finding the Right Testing Tool for the Job

Characterisation TestsForm: Ghost Inspector

Page 16: Finding the Right Testing Tool for the Job

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

Acceptance Tests

Page 18: Finding the Right Testing Tool for the Job

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

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

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

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

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

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

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

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

Acceptance TestsForm: PHPUnit at service level

Page 27: Finding the Right Testing Tool for the Job

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

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

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

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

Integration Tests

Page 32: Finding the Right Testing Tool for the Job

Integration TestsGoals:

— Test cross-boundary communication

— Test integration with concrete infrastructure

Page 33: Finding the Right Testing Tool for the Job

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

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

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

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

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

Unit Tests

Page 39: Finding the Right Testing Tool for the Job

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

Unit Tests:Scopes:

— Single classes

— Single classes + value objects?

— Extremely small units of code

Page 41: Finding the Right Testing Tool for the Job

Unit Tests:Times:

— Just before you implement

Page 42: Finding the Right Testing Tool for the Job

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

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

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

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

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

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

Thank You & Questions?

@s_bergmann@ciaranmcnulty

https://joind.in/talk/80dbd