Date post: | 06-May-2015 |
Category: |
Technology |
Upload: | naresh-jain |
View: | 2,782 times |
Download: | 3 times |
Copyright © 2013, AgileFAQs. All Rights Reserved.
Avatars of TDDRule of Diversity
Distrust all claims for “One True Way”
Naresh [email protected]
@nashjain http://nareshjain.com
Copyright © 2013, AgileFAQs. All Rights Reserved.
Key Questions
Are we building the right product?
Are we building the product right?
Business Facing
Technology/Implementation Facing
Copyright © 2013, AgileFAQs. All Rights Reserved.
Brian Marick’s Test Categorization
Business Facing
Technology/Implementation Facing
Supp
orts
Pro
gram
min
gC
ritique product
Before/While Coding Post Coding
Copyright © 2013, AgileFAQs. All Rights Reserved.
It Helps to Think of Tests this way...
Business Facing
Technology/Implementation Facing
Dri
ves
Dev
elop
men
t Critique productUnit Testing
Acceptance Testing Low-fi prototypes
Exploratory TestingUI and Usability Testing
Performance TestingSystem Tests
Business Facing
Technology/Implementation Facing
Dri
ves
Dev
elop
men
t Critique product
Outside In
Inside Out
Brian Marick’s Test Categorization
Add a Test
Run the Test
Make a little change
Run the Test
Refactor
Fail
Pass
Fail
Pass
TDD RhythmTest, Code, Refactor
Copyright © 2013, AgileFAQs. All Rights Reserved.
Acceptance Test Driven Development
Iteration
Automated Acceptance Tests
AutomatedAcceptance Tests
Story
Acceptance Criteria
Acceptance Criteria
ExploratoryTesting
Automated UI Tests
TESTS
PERFORMENCE
Automated Unit Test
Commercial Break!
Copyright © 2013, AgileFAQs. All Rights Reserved.
Tech Talks!
Copyright © 2013, AgileFAQs. All Rights Reserved.
Veterinarian Information System
It all started with...
Outside In: ATDDFitnesse Document:Assertions: 17 right, 0 wrong, 0 ignored, 0 exceptions
com.vis.billing.fixtures.PaidCashBill
account details
account number patient name owner name
1001 Fluffy Dave Atkins
procedure detailsname cost
Routine Office Visit 250
Rabies Vaccination 50
bill
account number? owner name? patient name? total? paid?
1001 Dave Atkins Fluffy 300 false
procedure details on the bill
name cost
Routine Office Visit 250
Rabies Vaccination 50
pay Cash
patient name? owner name? account number? bill no? payment method? amount paid?
Fluffy Dave Atkins 1001 1 Cash 300
check paid true
check total 0
Outside In: Output
ATDD: Another ExampleAcceptance 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 endend
Outside In: Output
Inside Out: Unit TDDpublic class ClinicTest { private Clinic clinic = new Clinic();
@Test public void amountOnTheReceiptShouldMatchBillableAmount() throws Exception { Billable billable = new Billable() { public int totalAmount() { return 0; } }; Account dave = new Account(101, "Dave");
Receipt rcpt = clinic.payCash(dave, billable); assertEquals("Amount on receipt does match procedure cost", billable.totalAmount(), rcpt.getAmount()); }
@Test public void customerPayesBillableAmountForCashTransaction() throws Exception { final int billableAmount = 56; class AmountCharged { int charged; }; final AmountCharged charged = new AmountCharged();
Billable billable = new Billable() { public int totalAmount() { return billableAmount; } };
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); }}
public class BillableTest {
private static final Account daveSAccount = new Account(101, "Dave"); private static final List<Service> services = new ArrayList<Service>();
@Test public void totalBillableAmountShouldBeZeroIfNoServicesAreProvided() { Billable bill = new Bill(daveSAccount, services); assertEquals("Total amount is not Zero", 0, bill.totalAmount()); }
@Test public void totalBillableAmountShouldBeTotalOfEachServiceProvided() { services.add(new Procedure("Rabies Vaccination", 250)); services.add(new Procedure("Regular office Visit", 50));
Billable bill = new Bill(daveSAccount, services);
assertEquals("Total Amount is not 300", 300, bill.totalAmount()); }
@After public void cleanUp() { services.clear(); }}
Inside Out: Output
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 shouldMakePaymentsAgainstAnAccount() { account.paid(bill); replay(account); clinic.pay(300, bill, account); verify(account); }
@Test public void shouldHaveZeroAmountDueOnReceiptIfCompletePaymentIsMade() { expect(bill.amount()).andReturn(300); replay(bill); Receipt receipt = clinic.pay(300, bill, account); verify(bill); assertEquals(300, receipt.amount()); 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()); }}
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); try { new Bill(account, null); } catch (NoPaymentDueException e) { // expected } verify(account); }
@After public void cleanUp() { services.clear(); }
@Test public void shouldCreateABillWithTheTotalCostOfAllTheServices() { IMocksControl control = createControl(); Service rabiesVaccination = control.createMock(Service.class); Service routineVisit = control.createMock(Service.class); services.add(rabiesVaccination); services.add(routineVisit);
expect(account.isPaymentDue()).andReturn(true); expect(account.unpaidServices()).andReturn(services); bill();
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); }}
Inside Out: Example Continued...
Inside Out: Output
Copyright © 2013, AgileFAQs. All Rights Reserved.
Where do you Stand?
Unit Test x Acceptance test
API x User Interface
State x Interaction
OO x Procedural
Easy x Core
Narrow x Broad
Drive Design x Validate Design
Copyright © 2013, AgileFAQs. All Rights Reserved.
Bonus Calculator
Sales Quota Commission % Tax % Result1200 1100 10 10 91200 1500 10 10 01200 1200 10 10 0
Copyright © 2013, AgileFAQs. All Rights Reserved.
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.
Sales TaxBasic 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:1 book at 12.491 music CD at 14.991 chocolate bar at 0.85
Output 1:1 book : 12.491 music CD: 16.491 chocolate bar: 0.85Sales Taxes: 1.50Total: 29.83
Input 2:1 imported box of chocolates at 10.001 imported bottle of perfume at 47.50
Output 2:1 imported box of chocolates: 10.501 imported bottle of perfume: 54.65Sales Taxes: 7.65Total: 65.15
Input 3:1 imported bottle of perfume at 27.991 bottle of perfume at 18.991 packet of headache pills at 9.751 box of imported chocolates at 11.25
Output 3:1 imported bottle of perfume: 32.191 bottle of perfume: 20.891 packet of headache pills: 9.751 imported box of chocolates: 11.85Sales Taxes: 6.70Total: 74.68
Copyright © 2013, AgileFAQs. All Rights Reserved.
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.
Medical System Age Calculating ProgramAge 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.
First Few Inside-Out Tests@RunWith(Parameterized.class)public class DurationTest extends FixedTimeTestCase {! private final Date date;! private final String result;
! public DurationTest(Object date, Object result) {! ! this.date = (Date) date;! ! this.result = (String) result;! }
! @Parameters! public static List<Object[]> data() {! ! return new ArrayList<Object[]>() {! ! ! {! ! ! ! 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 calculatesDurationSince() {! ! String value = Duration.since(date);! ! assertEquals("For " + date, result, value);! }
! @Override! protected Date currentTime() {! ! return oct11nth2011Afternoon;! }}
@Testpublic void canRegisterAndUnregisterLargestDuration() { assertEquals("31 Years", Duration.since(may3rd1980));
Duration.register("Decades", MILLISECONDS_PER_YEAR * 10); assertEquals("3 Decades", Duration.since(may3rd1980));
Duration.unregister("Decades"); assertEquals("31 Years", Duration.since(may3rd1980));}
@Testpublic void canRegisterAndUnregisterSmallestDuration() { assertEquals("0 Hours", Duration.since(oct11nth2011Morning));
Duration.register("Minutes", MILLISECONDS_PER_MINUTE); assertEquals("2 Minutes", Duration.since(oct11nth2011Morning));
Duration.unregister("Minutes"); assertEquals("0 Hours", Duration.since(oct11nth2011Morning));}
Copyright © 2013, AgileFAQs. All Rights Reserved.
Meeting Assistant
Copyright © 2013, AgileFAQs. All Rights Reserved.
First Few Outside-In Tests
@Testpublic void jackWantsThinkingTime() { jack().isAvailable(now).forEver(); firstAvailableSlotFor(THIRTY_MINS).is(now);}
@Testpublic void jackBusyForNextTwoHours() { jack().isAvailable(inTwoHours).forEver(); firstAvailableSlotFor(THIRTY_MINS).is(inTwoHours);}
@Testpublic void jackAndJillAreAvailableRightNowToMeet() { jack().isAvailable(now).forEver(); jill().isAvailable(now).forEver(); between(JACK, JILL).firstAvailableSlotFor(THIRTY_MINS).is(now);}
@Testpublic void jackIsAvailableLaterForARequiredDuration() { jack().isAvailable(now).forNext(TWENTY_MINS); jack().isAvailable(inTwoHours).forEver(); firstAvailableSlotFor(THIRTY_MINS).is(inTwoHours);}
@Test(expected = RuntimeException.class)public void jackHasNoTimeToThink() { jack().isNotAvailable(); assistant.firstAvailableTimeFor(participants, THIRTY_MINS);}
Copyright © 2013, AgileFAQs. All Rights Reserved.
Where do you Stand?
Unit Test x Acceptance test
API x User Interface
State x Interaction
OO x Procedural
Easy x Core
Narrow x Broad
Drive Design x Validate Design