Slide 1

Slide 1 text

TDD sucks! But that has not have to be!

Slide 2

Slide 2 text

Christian Fischer Software Engineering Coach http://agiledojo.de @agiledojo

Slide 3

Slide 3 text

TDD in a Nutshell Test Implementation Refactoring

Slide 4

Slide 4 text

Design Evolution

Slide 5

Slide 5 text

Design Evolution Test make my Design hard to change. When the Design changes due to new requirements, I have to change my tests everytime.

Slide 6

Slide 6 text

QueryParserTest Design Evolution „guitar“ -> [guitar] “red electric guitar“ -> [red, electric, guitar] „red guitar with gigbag“ -> [red,guitar,gigback] „red guitar and gigbag“ -> [red,guitar,gigback] QueryParser + parse(String query): String[] - removeStopwords(String[] words) : String[] „red guitar with 7 gigbag“ -> [red,guitar,gigback] - removeNumbers(String[] words) : String[]

Slide 7

Slide 7 text

QueryFilter QueryFilterTest QueryParserTest Design Evolution „guitar“ -> [guitar] “red electric guitar“ -> [red, electric, guitar] [red,guitar,with,gigback]-> [red,guitar,gigback] [red,guitar,and,gigback] -> [red,guitar,gigback] QueryParser + parse(query: String): String [] - removeStopwords(words: String[]) : String[] [red,guitar,7,gigback] -> [red,guitar,gigback] - removeNumbers(words: String[]) : String[] + filter(words: String[]): String[] + QueryParser(filter: QueryFilter) -setUpMocks / MockInteractionTest

Slide 8

Slide 8 text

QueryFilter QueryFilterTest QueryParserTest Design Evolution „guitar“ -> [guitar] “red electric guitar“ -> [red, electric, guitar] [red,guitar,with,gigback]-> [red,guitar,gigback] [red,guitar,and,gigback] -> [red,guitar,gigback] QueryParser + parse(query: String) - removeStopwords(words: String[]) : String[] [red,guitar,7,gigback] -> [red,guitar,gigback] - removeNumbers(words: String[]) : String[] + filter(words: String[]): String[] + QueryParser(filter: QueryParser) -setUpMocks „Guitar“ -> [guitar] - toLowerCase(word: String) : String - toSingular(word: String) : String “guitars“ -> [guitar]

Slide 9

Slide 9 text

QueryFilter QueryFilterTest QueryParserTest Design Evolution „guitar“ -> [guitar] “red electric guitar“ -> [red, electric, guitar] [red,guitar,with,gigback]-> [red,guitar,gigback] [red,guitar,and,gigback] -> [red,guitar,gigback] QueryParser + parse(query: String) - removeStopwords(words: String[]) : String[] [red,guitar,7,gigback] -> [red,guitar,gigback] - removeNumbers(words: String[]) : String[] + filter(words: String[]): String[] + QueryParser(filter: QueryFilter, normalizer: QueryNormalizer) -setUpMocks / MockInteractionTest QueryNormalizerTest „Guitar“ -> „guitar“ „guitars“ -> „guitar“ QueryNormalizer + normalize(word: String): String - toLowerCase(word: String) : String - toSingular(word: String) : String

Slide 10

Slide 10 text

Strong Coupling Parser Module QueryParser QueryFilter QueryNormalizer QueryParserTest Parser Tests QueryFilterTest QueryNormalizerTest public Class package private Class

Slide 11

Slide 11 text

Loose Coupling Parser Module QueryParser QueryFilter QueryNormalizer QueryParserTest Parser Tests QueryFilterTest QueryNormalizerTest public Class package private Class

Slide 12

Slide 12 text

Design Evolution Develop your Tests against the Module API.

Slide 13

Slide 13 text

Leaky Refactoring

Slide 14

Slide 14 text

Leaky Refactoring When I refactor my Code, the tests fail and I have to rewrite them.

Slide 15

Slide 15 text

Leaky Refactoring

Slide 16

Slide 16 text

Leaky Refactoring Refactoring: Split name into two fields.

Slide 17

Slide 17 text

Leaky Refactoring Treat your implementation code as a Blackbox and only test Behaviour.

Slide 18

Slide 18 text

Mocking Frameworks

Slide 19

Slide 19 text

Mocking Frameworks I have to painfully write all these Framework Mocks.

Slide 20

Slide 20 text

Mocking Frameworks

Slide 21

Slide 21 text

Mocking Frameworks Write Adapters and mock these.

Slide 22

Slide 22 text

Weak Unit Tests

Slide 23

Slide 23 text

Weak Unit Tests I feel like I am writing code just for the sake of Code Coverage.

Slide 24

Slide 24 text

Weak Unit Tests Does the Endpoint has the corrrect Path & Method? Does the Deserialization works as expected? Does the Serialization works as expected?

Slide 25

Slide 25 text

Weak Unit Tests Don‘t write Unit Tests for I/O components. Use Integration Tests instead.

Slide 26

Slide 26 text

Acceptance Testing

Slide 27

Slide 27 text

Acceptance Testing Acceptance Tests are the new Unit Tests.

Slide 28

Slide 28 text

Test Fixture Order Repository setUp Data MyShop <> Order REST Controller Order Mgmt RestAssured DBUnit ShopTest send/verify Request

Slide 29

Slide 29 text

Acceptance Testing „Delivery Date is estimated based on delivery address.“ Fixture: Test:

Slide 30

Slide 30 text

Debugging Order REST Controller Time Formatting Time Calculation Order Mgmt What went wrong? Time Parsing Order Repository

Slide 31

Slide 31 text

Test Pyramid Order Repository setUp Data MyShop <> Order REST Controller Order Mgmt RestAssured DBUnit ShopTest send/verify Request 5 5 5 1

Slide 32

Slide 32 text

Test Pyramid setUp Data MyShop <> RestAssured DBUnit ShopTest send/verify Request 5*5*5=125

Slide 33

Slide 33 text

E2E Test Tests should have a specific scope. Number of Tests decrease with scope range.

Slide 34

Slide 34 text

QA Triangle Coverage Efficiency Effectiveness

Slide 35

Slide 35 text

5 Rules for efficient and effective TDD 1 Develop your Tests against the Module API. 2 Test the Behaviour, not the Implementation. 4 Use Integration Tests for I/O-Components. 3 Don‘t mock external libraries, use Adapters. 5 Make use of the Test Pyramid.

Slide 36

Slide 36 text

no Multi- Tasking Protection from Overengineering Complexity Partitioning no Fear of Change zero Debug Time Testable Design TDD Benefits TDD

Slide 37

Slide 37 text

Fragen?