Pitfalls Of Tdd Adoption by Bartosz Bankowski

  • 1,351 views
Uploaded on

 

More in: Self Improvement
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,351
On Slideshare
0
From Embeds
0
Number of Embeds
2

Actions

Shares
Downloads
0
Comments
0
Likes
2

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Pitfalls of TDD Adoption Bartosz Baokowski
  • 2. Agenda • Intro • What is TDD? • Why to adopt it? • Experience • Test smells and patterns • Summary • Where to go next?
  • 3. About the author • Software developer • Agile coach/mentor • Open source contributor • Leader of Polish Agile User Group
  • 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. 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. 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. The Good, The Bad & The Ugly aka what to do and what to avoid in your tests
  • 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. 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. 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. 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. Ultimate Test Template @Test public void should...() throws Exception { //given ... //when ... //then ... }
  • 13. „Should” Reduce the chance tests will look like: But increase the chance for:
  • 14. Comments //given ... //when ... //then ... Increase the chance the test is focused around single behavior.
  • 15. Bloated fixture • One fixture to rule them all Test method 1 Fixture Test method 2 Test method 3 Test method 4
  • 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. Minimal fixture
  • 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. 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. 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. 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. 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. 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. 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. Simplify assertions • Never use conditionals! – You definately need a new example – ...or your example is broken
  • 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. Summary
  • 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. 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