99% is not enough

42
99% IS NOT ENOUGH

Upload: techkartenmacherei

Post on 15-Apr-2017

386 views

Category:

Software


2 download

TRANSCRIPT

99%IS NOT ENOUGH

Sebastian Thoß Kruno Knego Sebastian HeuerBackend Lead Backend Developer Developer Advocate

Goods and Bads• fully object-oriented

• easy refactoring thanks to 100% code coverage

• not enough automated acceptance tests

• dependencies to legacy software (database changes, API calls)

Code Coverage

100% != 100%

public function execute() { $orders = $this->orderService->getOrders($this->orderNumber); $json = $this->orderJsonMapper->map($orders);

return new CommandResult($json); }

Example

public function testExecute() { $service = $this->createMock(OrderService::class); $mapper = $this->createMock(OrderJsonMapper::class);

$order1 = $this->createMock(Order::class); $order2 = $this->createMock(Order::class);

$command = new GetOrdersCommand('123', $service, $mapper);

$service->expects($this->once()) ->method('getOrders') ->with('123') ->willReturn([$order1, $order2]);

$mapper->expects($this->once()) ->method('map') ->with([$order1, $order2]);

$command->execute(); }

100%!

public function execute() { $orders = $this->orderService->getOrders($this->orderNumber); $json = $this->orderJsonMapper->map($orders);

return new CommandResult(json_encode('{"foo":"bar"}')); }

Breaking Stuff

Still 100%!

Test Pyramid

UNIT TESTS

Unit Testing leads to SOLID(ish) code• Single Responsibility

• Open/Closed

• Liskov Substitution

• Interface Segregation

• Dependency Inversion

Test Pyramid

INTEGRATION TESTS

UNIT TESTS

Class 1 Class 2

Class 3Mock

Integration Test

Test Pyramid

ACCEPTANCE TESTS

INTEGRATION TESTS

UNIT TESTS

Class 1 Class 2

Class 3

Acceptance Test

Test Pyramid

ACCEPTANCE TESTS

INTEGRATION TESTS

UNIT TESTS

?

$$$

¢

<?php namespace Kartenmacherei\Phpughh;

use PHPUnit_Framework_TestCase;

class SmokeTest extends PHPUnit_Framework_TestCase { /** * @dataProvider furyUrlProvider * * @param Url $url */ public function testFuryUrl(Url $url) { $result = $this->sendGetRequest($url);

$this->assertSame(200, $result->getStatusCode()); $this->assertNotEmpty($result->getBody()); $this->assertLessThanOrEqual(100, $result->getTimeToFirstByteInMilliseconds()); }

Test Pyramid

ACCEPTANCE TESTS

INTEGRATION TESTS

UNIT TESTS

SMOKE TESTS

$$$

¢

Test Pyramid

ACCEPTANCE TESTS

INTEGRATION TESTS

SMOKE TESTS

92% COVERAG

E

UNIT TESTS

Test Pyramid

ACCEPTANCE TESTS

INTEGRATION TESTS

SMOKE TESTS

UNIT TESTS

100% COVERAG

E

Why 100%?

Why 100%?• Robustness

• Feeling of security when refactoring

• Fixing bugs is cheaper

• Reducing amount of major bugs found in production

• Broken Windows Theory

"Factory Denver5" by dliban licensed under CC BY-NC-ND 2 - https://flic.kr/p/73y9dg

"Factory Denver5" by dliban licensed under CC BY-NC-ND 2 - https://flic.kr/p/73y9dg

But what about…

• Setters?

• Factories?

• Trivial Classes?

Tips & Tricks

Strict PHPUnit Config<?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.6/phpunit.xsd" bootstrap="bootstrap.php" backupGlobals="false" backupStaticAttributes="false" beStrictAboutChangesToGlobalState="true" beStrictAboutOutputDuringTests="true" beStrictAboutTestsThatDoNotTestAnything="true" forceCoversAnnotation="true" beStrictAboutCoversAnnotation="true">

Mocking public function testCalculatorMultiplies() { $multiplier = $this->getMultiplierMock(); $calculator = new Calculator($multiplier); // (…) }

/** * @return PHPUnit_Framework_MockObject_MockObject|Multiplier */ private function getMultiplierMock() { return $this->createMock(Multiplier::class); }

@codeCoverageIgnore

• errorHandlers

• shutdownHandlers

Be very strict about excluding code from coverage!

@codeCoverageIgnoreBe very strict about excluding code from coverage!

/** * @param mixed $targetNode * * @throws WrongInstanceException */ private function ensureIsElement($targetNode) { if (!$targetNode instanceof fDOMElement) { // @codeCoverageIgnoreStart throw new WrongInstanceException('target node is not instance of fDOMElement'); // @codeCoverageIgnoreEnd } }

Don't test your privates!

• Uncovered private methods are probably obsolete

• "If covering private methods by only testing public methods is hard, there might be another class in there struggling to get out"

"Who's going to pay for all that?"Re

lative

Cost

of a B

ugfix

40x

80x

120x

160x

Requirements Design Code Developer Tests Acceptance Tests Operations

1x 5x 10x20x

50x

150x

Source: Barry Boehm, Keynote Address, EQUITY 2007.

https://www.instagram.com/kartenmacherei/

Q&A

https://www.facebook.com/kartenmacherei/ +49 40 468996861

[email protected]

http://www.kartenmacherei.de/recruiting