Test-Driven Development

TDD, BDD, KISS and YAGNI for Java developers

3176 Unit Tests

- 662 files, 163k lines

- we disable most of them

- dead weight, technical debt

- Test code is code

- QA has no idea what tests are doing

One class = one unit test

- Wrong idea

- Tests for protected/private methods

- What is a unit anyways?

 

 

 

Motivation

Agile test pyramid

Motivation

Source: agilecoachjournal.com

Test-driven Development

  • Write test first
  • Turn test from "red" to "green" quickly
  • Refactor as necessary
  • Focus on implementing the Use Case
  • Don't be afraid to write "bad" code
  • Test the Use Case, not the implementation

 

Behavior-driven Development

  • Focus on Use Case
  • Describe use case Acceptance Test in English
    • given "the user is signed in"
    • when "an e-mail arrives"
    • then "e-mail is assigned to user"
  • Creates reports of behavior of the app
  • ATDD: Product owners write acceptance tests
    • ==> lack of adoption

Behavior-driven Development - Example with JGiven

@Test
public void a_pancake_can_be_fried_out_of_an_egg_milk_and_flour() {
    given().an_egg().
        and().some_milk().
        and().the_ingredient( "flour" );

    when().the_cook_mangles_everything_to_a_dough().
        and().the_cook_fries_the_dough_in_a_pan();

    then().the_resulting_meal_is_a_pancake();
}
Scenario: a pancake can be fried out of an egg milk and flour

  Given an egg
    And some milk
    And the ingredient flour
   When the cook mangles everything to a dough
    And the cook fries the dough in a pan
   Then the resulting meal is a pan cake

How to TDD in Java? - Quick detour

OOP - the "good" parts

 

abstract class Animal {
  abstract String sound();
}
class Cat extends Animal {
  String sound() { return "Meow!"; }
}
class Dog extends Animal {
  String sound() { return "Woof!"; }
}

class AnimalController {
   String greet(String name, Animal animal) {
      return animal.sound() + " " + name);
   }
}

  • Inheritance
  • Polymorphism
  • Encapsulation

How to TDD in Java? - Dependencies

Abstractions

 

Don't do this👆

Arrows are reversed !

How to TDD in Java? - Service Surface area

OOP in Java, the bad parts:
Everything is a class

 

Huge surface area

Dedicated, small interface,

Data in/out

How to TDD in Java? - Use Cases

Test a Use Case

 

Find the right abstraction level(s)

  • Write test against an API
    • interface or abstract class
    • web service
  • Provide an initial implementation of the API
  • Refactor if necessary
  • Add more Use Cases

How to TDD in Java? - Use Cases

The Right Abstraction Level - APIs everywhere

How to TDD in Java? - Do's

Isolate the API/module/service under test

  • Mocking - if you absolutely have to
  • In-memory DB

Use Test Fixtures

Make tests hermetic

Describe behavior

Keep test code clean

 

DO'S

How to TDD in Java? - Dont's

Mock everything

Use DI in the small

Test implementation detail:

  • protected/private methods
  • test class per class

 

Test impl. choices/external services

(write quick unit test if unsure, but delete before commit!)

DON'T'S

TDD Benefits

  • Write a working use case first, refactor only when necessary

KISS - Keep it simple, stupid

YAGNI - You ain't gonna need it

DRY - Don't repeat yourself

  • Only implement necessary use cases
  • Little concern about future extensions
  • We can always refactor "green" -> "green"
  • Use Refactoring to factor out common code

More information/inspiration

 

Ian Cooper - TDD, where did it all go wrong

https://youtu.be/EZ05e7EMOLM?t=1259

 

Kent Beck, Test-Driven Development By Example

 

Test-Driven Development

By Jochen Bedersdorfer

Test-Driven Development

  • 657