Avatars of Test Driven Development (TDD)

4,052 views

Published on

It's easy to speak of test-driven development as if it were a single method, but there are several ways to approach it. In my experience, different approaches lead to quite different solutions.

In this hands-on workshop, with the help of some concrete examples, I'll demonstrate the different styles and more importantly what goes into the moment of decision when a test is written? And why TDDers make certain choices. The objective of the session is not to decide which approach is best, rather to highlight various different approaches/styles of practicing test-driven development.

By the end of this session, you will understand how TTDers break down a problem before trying to solve it. Also you'll be exposed to various strategies or techniques used by TDDers to help them write the first few tests.

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,052
On SlideShare
0
From Embeds
0
Number of Embeds
1,890
Actions
Shares
0
Downloads
65
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Avatars of Test Driven Development (TDD)

  1. 1. Avatars of TDD Rule of Diversity Distrust all claims for “One True Way” Naresh Jain naresh@agilefaqs.com @nashjain http://nareshjain.com Copyright © 2013, AgileFAQs. All Rights Reserved.
  2. 2. Key Questions Business FacingAre we building the right product?Are we building the product right? Technology/Implementation Facing Copyright © 2013, AgileFAQs. All Rights Reserved.
  3. 3. Brian Marick’s Test Categorization Before/While Coding Post Coding Business FacingSupports Programming Critique product Technology/Implementation Facing Copyright © 2013, AgileFAQs. All Rights Reserved.
  4. 4. It Helps to Think of Tests this way... Business Facing Acceptance Testing Exploratory TestingDrives Development Critique product Low-fi prototypes UI and Usability Testing Performance Testing Unit Testing System Tests Technology/Implementation Facing Copyright © 2013, AgileFAQs. All Rights Reserved.
  5. 5. Business FacingDrives Development Inside Out Critique product Outside In Technology/Implementation Facing Brian Marick’s Test Categorization
  6. 6. TDD RhythmTest, Code, Refactor Add a Test Pass Run the Test Fail Make a little change Fail Run the Test Pass Refactor
  7. 7. Acceptance Test Driven Development Iteration Automated Acceptance Acceptance Tests P E Criteria R F O RStory Automated M Unit Test E T Automated UI N E C Tests S E T S Automated Acceptance Tests Acceptance Exploratory Criteria Testing Copyright © 2013, AgileFAQs. All Rights Reserved.
  8. 8. Commercial Break!
  9. 9. Copyright © 2013, AgileFAQs. All Rights Reserved.
  10. 10. Tech Talks!
  11. 11. It all started with... VeterinarianInformation System Copyright © 2013, AgileFAQs. All Rights Reserved.
  12. 12. Outside In: ATDD Fitnesse Document: Assertions: 17 right, 0 wrong, 0 ignored, 0 exceptionscom.vis.billing.fixtures.PaidCashBill procedure details on the billaccount details name costaccount number patient name owner name Routine Office Visit 2501001 Fluffy Dave Atkins Rabies Vaccination 50procedure details pay Cashname cost patient name? owner name? account number? bill no? payment method? amount paid?Routine Office Visit 250 Fluffy Dave Atkins 1001 1 Cash 300Rabies Vaccination 50bill check paid trueaccount number? owner name? patient name? total? paid?1001 Dave Atkins Fluffy 300 false check total 0
  13. 13. Outside In: Output
  14. 14. ATDD: Another Example Acceptance test: class FluffyTest < Test::Unit::TestCase def test_examination_and_shots vet = Veterinarian.new clinic = Clinic.new "Main Line health" dave = Owner.new "Dave" fluffy = Patient.new "Fluffy" dave.has fluffy visit = clinic.visit(fluffy, vet) do |v| v.procedure "Rabies vaccination", 50 end invoice = visit.invoice assert_equal invoice.to_s, <<-INVOICE Routine visit: $200 Rabies vaccination: $50 Total: $250 INVOICE receipt = clinic.pay_for visit, 100 assert_equal receipt.to_s, <<-RECEIPT Paid $100 for Routine visit Paid $0 for Rabies vaccination Outstanding: $150 RECEIPT end end
  15. 15. Outside In: Output
  16. 16. Inside Out: Unit TDDpublic class ClinicTest { private Clinic clinic = new Clinic(); public class BillableTest { @Test public void amountOnTheReceiptShouldMatchBillableAmount() throws Exception { private static final Account daveSAccount = new Account(101, "Dave"); Billable billable = new Billable() { private static final List<Service> services = new ArrayList<Service>(); public int totalAmount() { return 0; } }; @Test Account dave = new Account(101, "Dave"); public void totalBillableAmountShouldBeZeroIfNoServicesAreProvided() { Billable bill = new Bill(daveSAccount, services); Receipt rcpt = clinic.payCash(dave, billable); assertEquals("Total amount is not Zero", 0, bill.totalAmount()); } assertEquals("Amount on receipt does match procedure cost", billable.totalAmount(), rcpt.getAmount()); } @Test @Test public void totalBillableAmountShouldBeTotalOfEachServiceProvided() { public void customerPayesBillableAmountForCashTransaction() throws Exception { services.add(new Procedure("Rabies Vaccination", 250)); final int billableAmount = 56; services.add(new Procedure("Regular office Visit", 50)); class AmountCharged { int charged; }; final AmountCharged charged = new AmountCharged(); Billable bill = new Bill(daveSAccount, services); Billable billable = new Billable() { assertEquals("Total Amount is not 300", 300, bill.totalAmount()); public int totalAmount() { } return billableAmount; } @After }; public void cleanUp() { services.clear(); Account dave = new Account(101, "Dave") { } public void charge(int amount) { } charged.charged = amount; } }; clinic.payCash(dave, billable); assertEquals("Account is not charged billable amount", billableAmount,charged.charged); }}
  17. 17. Inside Out: Output
  18. 18. Inside Out: Another Examplepublic class ChargeAccountForServices { private static final Billable bill = createMock(Billable.class); private static final Accountable account = createMock(Accountable.class); private static final Clinic clinic = new Clinic(); @Before public void setUp() { reset(account); reset(bill); } @Test public void shouldHaveZeroAmountDueOnReceiptIfCompletePaymentIsMade() { @Test expect(bill.amount()).andReturn(300); public void shouldMakePaymentsAgainstAnAccount() { replay(bill); account.paid(bill); Receipt receipt = clinic.pay(300, bill, account); replay(account); verify(bill); clinic.pay(300, bill, account); assertEquals(300, receipt.amount()); verify(account); assertEquals(0, receipt.amountDue()); } } @Test public void shouldDisplayAmountDueOnTheReceiptIfIncompletePaymentIsMade() { expect(bill.amount()).andReturn(500); replay(bill); Receipt receipt = clinic.pay(300, bill, account); verify(bill); assertEquals(300, receipt.amount()); assertEquals(200, receipt.amountDue()); } }
  19. 19. Inside Out: Example Continued...public class CreateBillForClientAccount { private static final List<Service> services = new ArrayList<Service>(); private static final Accountable account = createMock(Accountable.class); private Bill bill; @Before public void setUp() { reset(account); } @Test public void shouldThrowExceptionIfAccountIsNotDueForPayment() { expect(account.isPaymentDue()).andReturn(false); replay(account); @Test try { public void shouldCreateABillWithTheTotalCostOfAllTheServices() { new Bill(account, null); IMocksControl control = createControl(); } catch (NoPaymentDueException e) { Service rabiesVaccination = control.createMock(Service.class); // expected Service routineVisit = control.createMock(Service.class); } services.add(rabiesVaccination); verify(account); services.add(routineVisit); } expect(account.isPaymentDue()).andReturn(true); @After expect(account.unpaidServices()).andReturn(services); public void cleanUp() { bill(); services.clear(); } expect(rabiesVaccination.cost()).andReturn(250); expect(routineVisit.cost()).andReturn(50); control.replay(); assertEquals(300, bill.amount()); control.verify(); } private void bill() throws NoPaymentDueException { replay(account); bill = new Bill(account, null); verify(account); } }
  20. 20. Inside Out: Output
  21. 21. Where do you Stand? Unit Test x Acceptance test API x User Interface State x Interaction OO x Procedural Easy x Core Narrow x BroadDrive Design x Validate Design Copyright © 2013, AgileFAQs. All Rights Reserved.
  22. 22. Bonus CalculatorSales Quota Commission % Tax % Result1200 1100 10 10 91200 1500 10 10 01200 1200 10 10 0 Copyright © 2013, AgileFAQs. All Rights Reserved.
  23. 23. First Few Tests Inside-Out Tests @Test! public void noBonusForLowPerformers() {! ! whenSalesIs(0).andQuotaIs(100).thenIndividualBonusIs(0);! }! @Test! public void noBonusForAveragePerformers() {! ! whenSalesIs(100).andQuotaIs(100).thenIndividualBonusIs(0);! }! @Test! public void bonusIsBasedOnCommissionPercentage() {! ! whenSalesIs(110).andQuotaIs(10).andCommissionIs(100).thenIndividualBonusIs(100);! ! whenSalesIs(110).andQuotaIs(10).andCommissionIs(10).thenIndividualBonusIs(10);! }! @Test! public void bonusIsBasedOnCommissionPercentageAfterTax() {! ! whenSalesIs(110).andQuotaIs(10).andCommissionIs(100).andTaxIs(10).thenIndividualBonusIs(90);! ! whenSalesIs(110.02).andQuotaIs(10.01).andCommissionIs(10).andTaxIs(10).thenIndividualBonusIs(9);! } Copyright © 2013, AgileFAQs. All Rights Reserved.
  24. 24. Sales Tax Basic sales tax is applicable at a rate of 10% on all goods, except books, food, and medical products that are exempt. Import duty is an additional sales tax applicable on all imported goods at a rate of 5%, with no exemptions. When I purchase items I receive a receipt which lists the name of all the items and their price (including tax), finishing with the total cost of the items, and the total amounts of sales taxes paid. Write an application that prints out the receipt details for these shopping baskets...Input 1: Input 2: Input 3:1 book at 12.49 1 imported box of chocolates at 10.00 1 imported bottle of perfume at 27.991 music CD at 14.99 1 bottle of perfume at 18.99 1 imported bottle of perfume at 47.50 1 packet of headache pills at 9.751 chocolate bar at 0.85 1 box of imported chocolates at 11.25 Output 2:Output 1: 1 imported box of chocolates: 10.50 Output 3:1 book : 12.49 1 imported bottle of perfume: 54.65 1 imported bottle of perfume: 32.191 music CD: 16.49 1 bottle of perfume: 20.89 Sales Taxes: 7.651 chocolate bar: 0.85 1 packet of headache pills: 9.75 Total: 65.15Sales Taxes: 1.50 1 imported box of chocolates: 11.85Total: 29.83 Sales Taxes: 6.70 Total: 74.68 Copyright © 2013, AgileFAQs. All Rights Reserved.
  25. 25. First Few Outside-In Tests@Testpublic void checkOutEmptyCart() { assertTotalIs(0);}@Testpublic void checkOutAnExemptedDomesticItem() { cart.add(rs100DomesticBook); assertTotalIs(100);}@Testpublic void checkOutTaxableDomesticItem() { cart.add(rs100DomesticMusicCD); assertTotalIs(110);}@Testpublic void checkOutExemptedImportedItem() { cart.add(rs100ImportedBook); assertTotalIs(105);}@Testpublic void checkOutImportedItem() { cart.add(rs100ImportedMacBook); assertTotalIs(115);} Copyright © 2013, AgileFAQs. All Rights Reserved.
  26. 26. Medical System Age Calculating Program Age Reported in Greater than 1 Year <Patient Name> is # Years old > 1 Month & < 1 Year <Patient Name> is # Months old > 1 Day & < 1 Month <Patient Name> is # Days old > 1 Hr & < 1 Day <Patient Name> is # Hours old Doctors and Nurses might like to add and remove new Durations. For Ex: If they add Decade, and Patient’s age is greater than 10 years, then age should be reported as <Patient Name> is # Decades old.Similarly: If they add Week, and Patient’s age is greater than 7 Day, but less than a month, then age should be reported as <Patient Name> is # Weeks old. Copyright © 2013, AgileFAQs. All Rights Reserved.
  27. 27. First Few Inside-Out Tests@RunWith(Parameterized.class)public class DurationTest extends FixedTimeTestCase {! private final Date date;! private final String result; @Test public void canRegisterAndUnregisterLargestDuration() {! public DurationTest(Object date, Object result) { assertEquals("31 Years", Duration.since(may3rd1980));! ! this.date = (Date) date;! ! this.result = (String) result; Duration.register("Decades", MILLISECONDS_PER_YEAR * 10);! } assertEquals("3 Decades", Duration.since(may3rd1980));! @Parameters Duration.unregister("Decades");! public static List<Object[]> data() {! ! return new ArrayList<Object[]>() { assertEquals("31 Years", Duration.since(may3rd1980));! ! ! { }! ! ! ! add(new Object[] { may3rd1980, "31 Years" });! ! ! ! add(new Object[] { jan1st2011, "9 Months" });! ! ! ! add(new Object[] { oct1st2011, "10 Days" });! ! ! ! add(new Object[] { oct11nth2011Afternoon, "0 Hours" });! ! ! }! ! }; @Test! } public void canRegisterAndUnregisterSmallestDuration() {! @Test assertEquals("0 Hours", Duration.since(oct11nth2011Morning));! public void calculatesDurationSince() {! ! String value = Duration.since(date); Duration.register("Minutes", MILLISECONDS_PER_MINUTE);! ! assertEquals("For " + date, result, value); assertEquals("2 Minutes", Duration.since(oct11nth2011Morning));! } Duration.unregister("Minutes");! @Override assertEquals("0 Hours", Duration.since(oct11nth2011Morning));! protected Date currentTime() { }! ! return oct11nth2011Afternoon;! }} Copyright © 2013, AgileFAQs. All Rights Reserved.
  28. 28. Meeting Assistant Copyright © 2013, AgileFAQs. All Rights Reserved.
  29. 29. First Few Outside-In Tests@Testpublic void jackWantsThinkingTime() { jack().isAvailable(now).forEver(); @Test firstAvailableSlotFor(THIRTY_MINS).is(now); public void jackIsAvailableLaterForARequiredDuration() {} jack().isAvailable(now).forNext(TWENTY_MINS); jack().isAvailable(inTwoHours).forEver();@Test firstAvailableSlotFor(THIRTY_MINS).is(inTwoHours);public void jackBusyForNextTwoHours() { } jack().isAvailable(inTwoHours).forEver(); firstAvailableSlotFor(THIRTY_MINS).is(inTwoHours); @Test(expected = RuntimeException.class)} public void jackHasNoTimeToThink() { jack().isNotAvailable();@Test assistant.firstAvailableTimeFor(participants, THIRTY_MINS);public void jackAndJillAreAvailableRightNowToMeet() { } jack().isAvailable(now).forEver(); jill().isAvailable(now).forEver(); between(JACK, JILL).firstAvailableSlotFor(THIRTY_MINS).is(now);} Copyright © 2013, AgileFAQs. All Rights Reserved.
  30. 30. Where do you Stand? Unit Test x Acceptance test API x User Interface State x Interaction OO x Procedural Easy x Core Narrow x BroadDrive Design x Validate Design Copyright © 2013, AgileFAQs. All Rights Reserved.
  31. 31. Thank you Naresh Jainnaresh@agilefaqs.com Copyright © 2013, AgileFAQs. All Rights Reserved.

×