Transcript
Page 1: Automated tests - facts and myths

Automated testsFacts and myths

/ Wojciech Sznapka @sznapka

Page 2: Automated tests - facts and myths

Cześć

Page 3: Automated tests - facts and myths

An introductionI work in software industry for about 9 yearsCare a lot about robust and testable architecturesLoves software craftsmanship, sophisticated architectures, Big Dataand ice hockey

Page 4: Automated tests - facts and myths

Test DrivenDevelopment

What is this?

Page 5: Automated tests - facts and myths

Add a test

Page 6: Automated tests - facts and myths

Write an implementation

Page 7: Automated tests - facts and myths

Refactor code

Page 8: Automated tests - facts and myths

Repeat!

Page 9: Automated tests - facts and myths

What'simportant here?

Page 10: Automated tests - facts and myths

... to have tests

Page 11: Automated tests - facts and myths

You won’t go to hell if you’llwrite a test after declaring an

interface or prototyping aclass ...

Page 12: Automated tests - facts and myths

... but you’ll surely end up inhell, if there won’t be a test

coverage

Page 13: Automated tests - facts and myths

Myths aboutautomated tests

Page 14: Automated tests - facts and myths

Boss doesn't payfor automated tests

Page 15: Automated tests - facts and myths

It's a myth!A 2005 study found that using TDD meant writingmore tests and, in turn, programmers who wrote

more tests tended to be more productiveby American Scientists

Page 16: Automated tests - facts and myths

But this ain't that hard ...class RomanConverter{ protected $conversions = [ 1000 => 'M', 900 => 'CM', 500 => 'D', 400 => 'CD', 100 => 'C', 90 => 'XC', 50 => 'L', 40 => 'XL', 10 => 'X', 9 => 'IX', 5 => 'V', 4 => 'IV', 1 => 'I'];

public function convert($inArabic) { if (!is_numeric($inArabic)) { throw new \InvalidArgumentException('I convert numerics'); } if ($inArabic <= 0) { return ''; } list ($arabic, $roman) = $this->conversionFactorFor($inArabic);

return $roman . $this->convert($inArabic - $arabic); }

protected function conversionFactorFor($inArabic) { foreach ($this->conversions as $arabic => $roman) { if ($arabic <= $inArabic) { return [$arabic, $roman]; } } }}

Page 17: Automated tests - facts and myths

... start from obvious thingsclass RomanConverterTest extends PHPUnit_Framework_TestCase{ public function testEmpty() { $this->assertEquals('', (new RomanConverter)->convert('')); }}

Page 18: Automated tests - facts and myths

... provide some meat ...class RomanConverterTest extends PHPUnit_Framework_TestCase{ /** @dataProvider provideTestData */ public function testConversions($arabic, $roman) { $converter = new RomanConverter(); $this->assertEquals($roman, $converter->convert($arabic)); }

public function provideTestData() { return array[ [3497, 'MMMCDXCVII'], [1, 'I'], [2, 'II'], [6, 'VI'], [9, 'IX'], [40, 'XL'], [45, 'XLV'], [90, 'XC'], [100, 'C'], [400, 'CD'] ]; }}

Page 19: Automated tests - facts and myths

... test edge casesclass RomanConverterTest extends PHPUnit_Framework_TestCase{ /** @expectedException \InvalidArgumentException */ public function testEmpty() { (new RomanConverter)->convert('wtf I am passing here')); }}

Page 20: Automated tests - facts and myths

Help yourself with tests generationphpunit-skelgen --test RomanConverter

Page 21: Automated tests - facts and myths

... or using Symfony'sXSolveUnitSkelgenBundle

./app/console xsolve:skelgen:test Acme/ExampleBundle/Service/.

./app/console xsolve:skelgen:test Acme/*/Controller/*

Page 22: Automated tests - facts and myths

We are buildingtoo complicated

systemfor an automated tests

Page 23: Automated tests - facts and myths

TDD forces you to writecleaner code

Page 24: Automated tests - facts and myths

It's easier to test smaller unitsof code

Page 25: Automated tests - facts and myths

so you write smaller classeswhich are less coupledand that makes your system more stableand open for an extension in the future

Page 26: Automated tests - facts and myths

Your Object Oriented designbecomes S.O.L.I.D. compilant

and this is awesome!

Page 27: Automated tests - facts and myths

You will of course tacklecostly dependencies

Page 28: Automated tests - facts and myths

Use PHPUnit's mockframework or Mockery

Page 29: Automated tests - facts and myths

Fake it till you make itclass MockedTest extends PHPUnit_Framework_TestCase{ public function testNonExistingValueObjects() { $configuration = \Mockery::mock('\ConfigurationValueObject', [ 'getUrl' => 'http://tdd.sznapka.pl', 'getFormat' => 'xml']); $this->assertEquals('xml', $configuration->getFormat()); // OK }}

Page 30: Automated tests - facts and myths

Mock thingsthat can't be tested quickly or non-

reproducableclass MockedTest extends PHPUnit_Framework_TestCase{ public function testApiCalls() { $buzzMock= \Mockery::mock('\Buzz\Browser'); $buzzMock->shouldReceive('get') ->andReturn('<response><mood>Awesomity</mood></response>');

// this also is wise solution, to write xml fixtures in file // $buzzMock->shouldReceive('get')->once() // ->andReturn(file_get_contents(__DIR__ . '/fixtures.xml'));

$api = new \ApiConsumer($buzzMock); $api->assertEquals('Awesomity', $api->getCurrentMood()); // OK }}

Page 31: Automated tests - facts and myths

Expect declared behaviorsclass MockedTest extends PHPUnit_Framework_TestCase{ public function testExpectationsDeclarations() { $buzzMock= \Mockery::mock('\Buzz\Browser'); $buzzMock->shouldReceive('get') ->andReturn('<response><mood>Awesomity</mood></response>');

$loggerMock = \Mockery::mock('\Monolog\Logger'); // we just want to be sure that Logger::info was called only once $loggerMock->shouldReceive('info')->once();

$api = new \ApiConsumer($buzzMock, $loggerMock); $api->assertEquals('Awesomity', $api->getCurrentMood()); // OK }}

Page 32: Automated tests - facts and myths

Be prepared for failuresand check if you prepared for unexpected situations

class MockedTest extends PHPUnit_Framework_TestCase{ /** @expectedException \MyExceptionWrapper */ public function testFailedConnection() { $buzzMock= \Mockery::mock('\Buzz\Browser'); $buzzMock->shouldReceive('get') ->andThrow('\Buzz\Exception\ClientException');

$loggerMock = \Mockery::mock('\Monolog\Logger'); $loggerMock->shouldReceive('info')->never(); $loggerMock->shouldReceive('err')->once();

(new \ApiConsumer($buzzMock, $loggerMock))->getCurrentMood(); }}

Page 33: Automated tests - facts and myths

We providingAPI for external

consumersit can't be tested...

Page 34: Automated tests - facts and myths

Use Symfony's WebTestCaseto test your API

I call it integration tests

Page 35: Automated tests - facts and myths

Call your API and check if itreturns prepared data

class ExpenditureControllerTest extends WebTestCase{ use IsolatedTestsTrait; // it resets test environment

public function testGetListInJson() { $client = static::createClient(); $client->request('GET', '/expenditures.json'); $json = json_decode($client->getResponse()->getContent());

$this->assertTrue($client->getResponse()->isSuccessful()); $this->assertCount(80, $json); $this->assertGreaterThanOrEqual( new \DateTime($json[79]->created_at), new \DateTime($json[0]->created_at)); }}

Page 36: Automated tests - facts and myths

Use fixtures and resetenvironment

IsolatedTestsTrait should do the trick

Page 37: Automated tests - facts and myths

Steps required to effectivelyrun in isolation

1. configure PDO SQLite in file2. create database3. drop schema4. load fixtres5. copy database as a backup6. copy database from backup for every test7. delete database backup after test suite

Page 38: Automated tests - facts and myths

Requirementschanges

frequentlywe can't keep up with unit

tests

Page 39: Automated tests - facts and myths

Use behavioralapproach

Behat in PHP

Page 40: Automated tests - facts and myths

Describe features as scenariosIt will be readable for: business, developers and machines

Page 41: Automated tests - facts and myths

Perfectly fits into Agileprocess

Page 42: Automated tests - facts and myths

Simple exampleFeature: look for a job In order to find cool job As an aspiring programmer I need to be able to list job offers

Scenario: list offers for PL version Given I am on "/" Then I should see "Dołącz do teamu" And click "Dołącz do teamu" Then I should be on "/kariera" And I should see "PHP Senior Developer (Gliwice)"

Scenario: no offers for EN site Given I am on "/en" Then I should not see "Dołącz do teamu" And I should not see an "#join-us" element

Page 43: Automated tests - facts and myths

Our tests areslow!

Page 44: Automated tests - facts and myths

This could be true ...

Page 45: Automated tests - facts and myths

Always use in-memory sqlitedatabase

Or create clean sqlite database and copyit for every test

Page 46: Automated tests - facts and myths

Group your testsUse PHPUnit's @group or Behat's @tag

Page 47: Automated tests - facts and myths

Create "smoke tests" groupsThose should be fast test, which ensures your system is most likely

stable

Page 48: Automated tests - facts and myths

Slower tests should run duringnight

Page 49: Automated tests - facts and myths

Facts

Page 50: Automated tests - facts and myths

It gives you confidenceabout changes and your code

Page 51: Automated tests - facts and myths

Team is able to rapidlyexperiment with code

Page 52: Automated tests - facts and myths

TDD enforces betterObject Oriented design

Smaller units of code and lower coupling always leads to betterunderstanding of the codebase by future devs

Page 53: Automated tests - facts and myths

End user experiences betterquality

lower 500 error ratio in the production

Page 54: Automated tests - facts and myths

Happier users↓

more $$$ in future

Page 55: Automated tests - facts and myths

Conclusion

Page 56: Automated tests - facts and myths

Setting up an workingenvironment for automated

testsis timely costly at the begining, but it pays off in the future

Page 57: Automated tests - facts and myths

System without any kind ofautomated tests

has big potential to be a big ball of mud

Page 58: Automated tests - facts and myths

Good coverage can be easilyachieved with

mix of unit, functional and behavioral tests

Page 59: Automated tests - facts and myths

You need to build andcultivate

TDD culture in your surrounding

Page 60: Automated tests - facts and myths

Thank you so much forattending!

Feedback is much appreciated

[email protected]

Twitter: @sznapkaGitHub: @wowo

Page 61: Automated tests - facts and myths

Join team :-)XSolve


Top Related