Upgrade to Pro — share decks privately, control downloads, hide ads and more …

My Top 10 PHPUnit Tips And Tricks

My Top 10 PHPUnit Tips And Tricks

Presented on June 26 2020 at the Dutch PHP Conference Online Edition.
https://schedule.phpconference.nl/talk/2
---------------------------------------------------------------
Of course you test your code... you may even use test driven development. But do those tests really add value ? Are your tests actually testing your code ? Or are they just there to satisfy the CI process ?

In this talk Juliette will focus on all the things she's learned in years of writing and reviewing tests, the pitfalls she fell into, and the tips and tricks she learned along the way.
---------------------------------------------------------------

Links:
Code used in the presentation:
https://github.com/jrfnl/top-10-phpunit-tips-tricks-demo

PHPUnit Docs:
https://phpunit.readthedocs.io/

Infection:
Docs: https://infection.github.io/
Demo: https://youtu.be/ADKyTlaH6e4

More Decks by Juliette Reinders Folmer

Other Decks in Programming

Transcript

  1. My Top 10 PHPUnit Tips & Tricks Juliette Reinders Folmer

    Tweet about it: @jrf_nl #DPC20 Olivier Issaly
  2. Before we start...  Follow along with the code samples

    used: https://github.com/jrfnl/ top-10-phpunit-tips-tricks- demo  Discuss in Slack channel: #phpunit-tips-and-tricks davidjohn
  3. Have the basic setup in place [1] In composer.json: {

    "require-dev" : { "phpunit/phpunit": "^8.0 || ^9.0" }, "autoload": { "classmap": ["src/"] }, "autoload-dev": { "classmap": ["tests/"] } }
  4. Have the basic setup in place [2] In phpunit.xml.dist: <?xml

    version="1.0" encoding="UTF-8"?> <phpunit bootstrap="./vendor/autoload.php" colors="true" > <testsuites> <testsuite name="Foo"> <directory suffix="Test.php"> ./tests/ </directory> </testsuite> </testsuites> </phpunit> --generate-configuration
  5. Start Small (but start somewhere) <?php namespace PHPUnit_Demo; class Foo

    { static function stripQuotes($string) { return preg_replace( '`^([\'"])(.*)\1$`Ds', '$2', $string ); } } @562a010
  6. Start Small (but start somewhere) <?php namespace PHPUnit_Demo\Tests; use PHPUnit\Framework\TestCase;

    use PHPUnit_Demo\Foo; class FooTest extends TestCase { public function testStripQuotes() { $result = Foo::stripQuotes('"text"'); $this->assertEquals('text', $result); } } @afda386
  7. Use the Right Assertion <?php namespace PHPUnit_Demo\Tests; use PHPUnit\Framework\TestCase; use

    PHPUnit_Demo\Foo; class FooTest extends TestCase { public function testStripQuotes() { $result = Foo::stripQuotes('"text"'); $this->assertEquals('text', $result); $this->assertSame('text', $result); } } @ef6fa43
  8. <?php public function testStripQuotes() { $result = Foo::stripQuotes('"some text"'); $this->assertSame('some

    text', $result); $result = Foo::stripQuotes("some 'text'"); $this->assertSame("some 'text'", $result); $result = Foo::stripQuotes(false); $this->assertSame('', $result); } Don't Just Test the Happy Path @ef108e2
  9. <?php public function testStripQuotes() { $result = Foo::stripQuotes('"some text"'); $this->assertSame('some

    text', $result); $result = Foo::stripQuotes("some 'text'"); $this->assertSame("some 'text'", $result); $result = Foo::stripQuotes(false); $this->assertSame('', $result); } Use Fail Messages @2ccceaf
  10. <?php public function testStripQuotes() { $result = Foo::stripQuotes('"some text"'); $this->assertSame('some

    text', $result, 'stripping quotes failed'); $result = Foo::stripQuotes("some 'text'"); $this->assertSame("some 'text'", $result, 'failed with quotes in string'); $result = Foo::stripQuotes(false); $this->assertSame('', $result, 'failed with non-string input'); } Use Fail Messages @2ccceaf
  11. Test Method Data Provider /** * Test Foo::stripQuotes(). * *

    @dataProvider dataStripQuotes * * @param mixed $in Function input. * @param string $out Expected output. * * @return void */ public function testStripQ($in, $out) { $result = Foo::stripQuotes($in); $this->assertSame($out, $result); } /** * Data provider. * * @return array[] */ public function dataStripQuotes() { return [ ['"some text"', 'some text'], ["some 'text'", "some 'text'"], [false, ''], ]; } @2ccceaf
  12. Named Test Cases /** * Data provider for the testStripQuotes()

    test. * * @return array[] */ public function dataStripQuotes() { return [ 'double quoted text' => ['"some text"', 'some text'], 'quotes with quoted text within' => ["some 'text'", "some 'text'"], 'not string input - bool' => [false, ''], ]; } @13e218b
  13. Filter Options Filter Shortcuts --filter TestNamespace --filter TestClass --filter testMethod

    --filter 'TestNS\\TClass::testMethod' --filter 'TestNS\\TestClass' --filter '/::testMethod .*"name"/' --filter '/::testMethod .*#5$/' --filter '/::testMethod .*#(1|2|5)$/' --filter 'testMethod#5' --filter 'testMethod#4-6' --filter '#1' --filter '#1-3' --filter 'testMethod@named test case' --filter 'testMethod@name.*case' --filter '@named test case' --filter '@named.*case'
  14. <?php namespace PHPUnit_Demo; class Foo { static function stripQuotes($string) {

    return preg_replace( '`^([\'"])(.*)\1$`Ds', '$2', $string ); } }
  15. Enabling Code Coverage [1] <?xml version="1.0" encoding="UTF-8"?> <phpunit beStrictAboutCoversAnnotation="true" forceCoversAnnotation="true"

    > ... <filter> <whitelist addUncoveredFilesFromWhitelist="true"> <directory suffix=".php">src</directory> </whitelist> </filter> <logging> <log type="coverage-clover" target="build/logs/clover.xml"/> </logging> </phpunit> @1710ccb See also: feature/ update-config-for- phpunit-9.3
  16. Enabling Code Coverage [2] <?php class FooTest extends TestCase {

    /** * Test Foo::stripQuotes(). * * @dataProvider dataStripQuotes * * @covers \PHPUnit_Demo\Foo::stripQuotes */ public function testStripQuotes($in, $out) { $result = Foo::stripQuotes($input); $this->assertSame($expected, $result); } @1710ccb
  17. Simplify { "scripts" : { "test": [ "vendor/bin/phpunit --no-coverage" ],

    "coverage": [ "vendor/bin/phpunit" ], "coverage-local": [ "vendor/bin/phpunit --coverage-html ./build/coverage-html" ] } } @1710ccb
  18. Conditionally Skipping Tests [1] public function testIsCountable($input, $expected) { if

    (\version_compare(\PHP_VERSION_ID, '70300', '<')) { return; } $this->assertSame($expected, myCountable($input)); } example/test-skipping
  19. Conditionally Skipping Tests [2] public function testIsCountable($input, $expected) { if

    (\version_compare(\PHP_VERSION_ID, '70300', '<')) { $this->markTestSkipped(); return; } $this->assertSame($expected, myCountable($input)); } example/test-skipping
  20. Conditionally Skipping Tests [2] public function testIsCountable($input, $expected) { if

    (\version_compare(\PHP_VERSION_ID, '70300', '<')) { $this->markTestSkipped( 'This test requires PHP 7.3.0+' ); } $this->assertSame($expected, myCountable($input)); } example/test-skipping
  21. Conditionally Skipping Tests [4] /** * @requires PHP >= 7.3.0

    */ public function testIsCountable($input, $expected) { if (\version_compare(\PHP_VERSION_ID, '70300', '<')) { $this->markTestSkipped( 'This test requires PHP 7.3.0+' ); return; } $this->assertSame($expected, myCountable($input)); } example/test-skipping
  22. PHPUnit Support v Compatible with: 9 PHP 7.3, 7.4 (support

    ends Feb 2022) 8 PHP 7.2, 7.3, 7.4 (support ends Feb 2021) 7 PHP 7.1, 7.2, 7.3 6 PHP 7.0, 7.1, 7.2 5 PHP 5.6, 7.0, 7.1 4 PHP 5.3, 5.4, 5.5, 5.6 Seemann
  23. Cross-version Compatible Fixtures public static setupBeforeClass() : void { self::$db

    = new DBConnector(); } public static tearDownAfterClass() : void { self::$db->disconnect(); }
  24. Cross-version Compatible Fixtures /** * @beforeClass */ public static setupBeforeClass()

    : void { public static setupDBConnection() { self::$db = new DBConnector(); } /** * @afterClass */ public static tearDownAfterClass() : void { public static disconnectDB() { self::$db->disconnect(); unset(self::$db); }
  25. Thanks! @jrf_nl @jrfnl Any questions ? Feedback: https://joind.in/talk/2d124 Slides: https://speakerdeck.com/jrf

    Code: https://github.com/jrfnl/ top-10-phpunit-tips-tricks-demo Docs: https://phpunit.readthedocs.io/