Pitfalls of TDD Adoption

     Bartosz Baokowski
Agenda
•   Intro
•   What is TDD?
•   Why to adopt it?
•   Experience
•   Test smells and patterns
•   Summary
•   Where t...
About the author
•   Software developer
•   Agile coach/mentor
•   Open source contributor
•   Leader of Polish Agile User...
What is TDD?
• It seems everyone knows it nowadays.
• At least everyone talks about it.
• Well, why do we still have bad c...
Why to adopt it?
•   Explore system behavior.
•   Create a specification.
•   Drive code design.
•   Think about quality.
...
Experience
• TDD classes on major universities in Krakow,
  Poland since 2007.
• TDD workshops at various conferences in
 ...
The Good, The Bad & The Ugly
      aka what to do and what to avoid in your tests
What to test?
• Methods vs Test Cases = 1:1 relationship
• How to name a test method?
    class Flights {            class...
What to test?
• Implicit constructor testing
        @Test
        public void testConstructor() {
          Flight flight...
It’s about behavior
• ...so write examples:
  – tell me what your system does NOT have yet?
  – answer it in programming l...
Coding by example
• User story:
   – As a user I want to get a number of available seats for a
     given flight
         ...
Ultimate Test Template
@Test
public void should...() throws Exception {
 //given
 ...

    //when
    ...

    //then
    ...
„Should”
Reduce the chance tests will look like:




But increase the
  chance for:
Comments
//given
 ...

//when
...

//then
...


  Increase the chance the test is focused around
  single behavior.
Bloated fixture
• One fixture to rule them all


                          Test method 1
         Fixture
                ...
Healthy fixture
• Extract only common parts to setup method
                         @Test
You want to avoid it.
         ...
Minimal fixture
Noisy fixture
// given
Flight flight1 = new Flight(1, new Market("KRK", "YVR"), new Date(), 50);
Flight flight2 = new Flig...
Noisy fixture refactoring
• Hide irrelevant data with creation method
      // given
      Flight flight1 = createFlightFr...
Fluent builders
• Make code more readable
• Worth to try if too many creation methods
• Require time to build
  Flight fli...
Stable test data
• Golden rule:
  – No matter how many times you run the test it
    should always give the same results!
...
One behavior per method
• If you have more than one statement in when,
  you may need a new example.
• If you have asserti...
One verification per test
• Use assertions only in then block
• Make them as expressive as possible
  assertEquals(2, flig...
Simplify assertions
• You don’t want to guess what you are
  expecting. It’s expectation anyway!
     assertEquals((a + b ...
Simplify assertions
• Never use conditionals!
  – You definately need a new example
  – ...or your example is broken
Testing exceptions
• It seems fine:
     @Test(expected=IllegalFlightNumberException.class)
     public void shouldFailFor...
Summary
How to make it work?
• Train your people
• Give them simple rules to adhere to (e.g. test
  template!)
• Encourage pair pr...
Where to go next?
• Online:
  – xunitpatterns.com
  – behavior-driven.org
• Offline:
  – „xUnit Test Patterns” by Gerard M...
Upcoming SlideShare
Loading in...5
×

Pitfalls Of Tdd Adoption by Bartosz Bankowski

1,414

Published on

Published in: Self Improvement
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,414
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
0
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Pitfalls Of Tdd Adoption by Bartosz Bankowski

  1. 1. Pitfalls of TDD Adoption Bartosz Baokowski
  2. 2. Agenda • Intro • What is TDD? • Why to adopt it? • Experience • Test smells and patterns • Summary • Where to go next?
  3. 3. About the author • Software developer • Agile coach/mentor • Open source contributor • Leader of Polish Agile User Group
  4. 4. What is TDD? • It seems everyone knows it nowadays. • At least everyone talks about it. • Well, why do we still have bad code?
  5. 5. Why to adopt it? • Explore system behavior. • Create a specification. • Drive code design. • Think about quality. • Last, but not least – build executable and automated tests.
  6. 6. Experience • TDD classes on major universities in Krakow, Poland since 2007. • TDD workshops at various conferences in Poland. • TDD coaching and trainings at Sabre Holdings.
  7. 7. The Good, The Bad & The Ugly aka what to do and what to avoid in your tests
  8. 8. What to test? • Methods vs Test Cases = 1:1 relationship • How to name a test method? class Flights { class FlightsTest { addFlight(...); testAddFlight(...); getFlight(...); testGetFlight(...); getFlightSeats(...); testGetFlightSeats(...); getCheapestSeat(...); testGetCheapestSeat(...); bookSeat(...); testBookSeat(...); } }
  9. 9. What to test? • Implicit constructor testing @Test public void testConstructor() { Flight flight = new Flight(); assertEquals(...); assertEquals(...); } @Test public void testConstructor() { Flight flight = new Flight(); assertNotNull(flight); }
  10. 10. It’s about behavior • ...so write examples: – tell me what your system does NOT have yet? – answer it in programming language – answer giving an example
  11. 11. Coding by example • User story: – As a user I want to get a number of available seats for a given flight class FlightTest { @Test public void shouldReturnNumberOfAvailableSeats() { // given Flight flight = new Flight(); flight.addSeats(10); // when int numberOfSeats = flight.getNumberOfAvailableSeats(); // then assertEquals(10, numberOfSeats); } }
  12. 12. Ultimate Test Template @Test public void should...() throws Exception { //given ... //when ... //then ... }
  13. 13. „Should” Reduce the chance tests will look like: But increase the chance for:
  14. 14. Comments //given ... //when ... //then ... Increase the chance the test is focused around single behavior.
  15. 15. Bloated fixture • One fixture to rule them all Test method 1 Fixture Test method 2 Test method 3 Test method 4
  16. 16. Healthy fixture • Extract only common parts to setup method @Test You want to avoid it. public void testAvailableSeatsCount() throws { assertEquals(0, f.getAvailableSeats()); f.addSeat(new Seat(1, 100)); assertEquals(1, f.getAvailableSeats()); } • Minimize it • Use creation methods where appropriate
  17. 17. Minimal fixture
  18. 18. Noisy fixture // given Flight flight1 = new Flight(1, new Market("KRK", "YVR"), new Date(), 50); Flight flight2 = new Flight(2, new Market("KRK", "YVR"), new Date(), 30); Flight flight3 = new Flight(3, new Market("HKG", "YVR"), new Date(), 60); List<Flight> flights = new ArrayList<Flight>(); flights.add(flight1); flights.add(flight2); flights.add(flight3); FlightManager flightManger = new FlightManager(flights); // when List<Flight> flights = flightManger .getFlightsFromOrigin("KRK"); // then assertEquals(2, flights.size()); assertTrue(flights.contains(flight1)); assertTrue(flights.contains(flight2));
  19. 19. Noisy fixture refactoring • Hide irrelevant data with creation method // given Flight flight1 = createFlightFromOrigin("KRK"); Flight flight2 = createFlightFromOrigin("KRK"); Flight flight3 = createFlightFromOrigin("HKG"); • Make it simple List<Flight> flights = new ArrayList<Flight>(); flights.add(flight1); flights.add(flight2); flights.add(flight3); FlightManager flightManger = new FlightManager(flights); FlightManager flightManager = new FlightManager(asList(flight1, flight2, flight3));
  20. 20. Fluent builders • Make code more readable • Worth to try if too many creation methods • Require time to build Flight flight = new Flight(1, new Market("KRK", "YVR"), new Date()); Flight flight = buildFlight().number(1).between("KRK", "YVR").today().build();
  21. 21. Stable test data • Golden rule: – No matter how many times you run the test it should always give the same results! • Random test data • Time & date tests can be tricky
  22. 22. One behavior per method • If you have more than one statement in when, you may need a new example. • If you have assertions outside then, you may need a new example.
  23. 23. One verification per test • Use assertions only in then block • Make them as expressive as possible assertEquals(2, flights.size()); assertTrue(flights.contains(flight1)); assertTrue(flights.contains(flight2)); Custom assertion: assertFlightsContainOnly(flights, flight1, flight2); Hamcerst: assertThat(flights, hasItems(flight1, flight2)); FEST-Assert: assertThat(flights).containsOnly(flight1, flight2);
  24. 24. Simplify assertions • You don’t want to guess what you are expecting. It’s expectation anyway! assertEquals((a + b + c) / 3, average); • Loops are bad. int pos = 0; for (ToolGroup group: groups) { assertTrue(pos <= group.getLocation()); pos = group.getLocation(); }
  25. 25. Simplify assertions • Never use conditionals! – You definately need a new example – ...or your example is broken
  26. 26. Testing exceptions • It seems fine: @Test(expected=IllegalFlightNumberException.class) public void shouldFailForWrongFlightNumber() throws Exception { FlightManager flightManager = new FlightManager(); flightManager.addFlight(new Flight(10)); flightManager.addFlight(new Flight(15)); flightManager.getFlight(50); } • But what if new Flight() can throw same exception?
  27. 27. Summary
  28. 28. How to make it work? • Train your people • Give them simple rules to adhere to (e.g. test template!) • Encourage pair programming • ...or at least code reviews • Do not listen to excuses – I don’t have time to write tests!
  29. 29. Where to go next? • Online: – xunitpatterns.com – behavior-driven.org • Offline: – „xUnit Test Patterns” by Gerard Meszaros – „Growing Object-Oriented Software, Guided by Tests” by Steve Freeman, Nat Pryce – „Behavior Driven Development in Ruby with RSpec” by David Chelimsky, Aslak Hellesoy

×