What I'm hearing a lot: “ I'd really like to write more tests but I don't get any practical value from them. It takes too much time, or it is too hard. Therefore I don't enjoy it or stopped doing it. (I totally understand that!) 4 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Another popular opinion: ‘ Integration tests are superior to unit tests. Do not waste your time with unit tests. (at least they are writing tests!) 5 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Why all the frustration? The project smells Buggy tests High test maintenance cost Production bugs Developers not writing tests 10 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Why all the frustration? The behavior smells Fragile Test Erratic Test Slow Test Frequent Debugging Manual Intervention 11 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Fixture setup strategy Prebuilt xture Shared xture shared by whole test suite OR shared by test case Fresh xture 25 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Problem increasing cost of changes Possible solutions Extract method refactoring In setup: Creation method for fresh xture Finder method for shared xture In veri cation: Custom assertion method 28 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Problem increasing cost of changes Possible solutions Extract class refactoring In setup: Test data builder In veri cation: Custom constraint 29 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Testing pattern Constraint class IsMeaningOfLife extends \PHPUnit\Framework\Constraint { protected function matches($other) { return $other === 42; } protected function failureDescription($other) { return sprintf( "%s is not the meaning of life, the universe and everything", $other ); } } 30 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Problem Hard to read test as documentation Possible solutions Extract creation methods or assertions with relevant parameters For xtures: Test data builder 36 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Problem Hard to understand cause and effect Purpose of typical test data (foo, bar, 1, 42) is unclear Possible solutions Introduce variables or constants 38 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Testing smell Mystery guest Set up or veri cation relies on information that's not visible in the test Filename Database record General xture 39 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Problem Hard to understand cause and effect Risk of somebody else editing external source without knowing how it's used Possible solutions Fresh xture for each test Test data builders instead of xture scripts Create les in test For shared xture: Accurately named nder methods 42 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Shared Fixture Using attribute $this->assertTrue($this->product->isNew(), 'Product should be new'); Using nder method $this->assertTrue( $this->getRecentlyAddedProduct()->isNew(), 'Product should be new' ); private function getRecentlyAddedProduct() { return $this->product; } 43 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Problem Hard to tell apart setup, exercise and veri cation Harder to localize defects Possible solutions Single condition tests 45 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Testing pattern Given...When...Then... $this->given_stock_item_with_qty(2); $this->when_stock_item_is_changed_to(0); $this->then_loaded_stock_item_qty_should_be('0.0000'); Readable high level test methods Clear phases: setup (given), exercise (when) and veri cation (then) Convert variables ($savedStockItem) to properties Additional methods can also start with and_ 46 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Problem Coupling test to implementation Test is hard to read Possible solutions Use real domain objects where possible Refactor production code Use custom stub or fake objects with simpler setup 48 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Testing pattern Fake object Test speci c implementation without external dependencies 49 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Testing Smell Meaningless test names public function testProcessValidStoreCodeCase1() { // ... } public function testProcessValidStoreCodeCase2() { // ... } public function testProcessValidStoreCodeCase3() { // ... } 52 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Problem Failures in test results are unclear Possible solutions Write meaningful test names Use named keys in data provider arrays return [ 'meaningful description of case 1' => [ ... ], 'meaningful description of case 2' => [ ... ], ] 53 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Problem Failures in test results are unclear Possible solutions use the $message parameter in assert methods to add custom message 55 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Problem Harder to understand the test Harder to write the test correctly Possible solutions Write separate test cases, extract duplicated logic Make sure, tests are deterministic 57 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
More smells Test logic in production General xture Using resources (DB, HTTP) in unit tests Indirect testing "Inappropiate intimacy" 58 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler
Conclusion Maintainability and stability of tests can be greatly improved by taking care of the test architecture. Watch out for these typical problems. Get rid of them. 59 / 60 #MM18PL Fabian Schmengler /> Dealing With Testing Fatigue @fschmengler