Hva var egentlig spørsmålet? Johannes Brodwall
FitNesse eksempel #1
© Steria En public void femereSkalGiAntall() throws Exception { assertEquals(0, scoreForKast("femere", 1, 2, 2, 2, 1)); assertEquals(10, scoreForKast("femere", 1, 2, 5, 5, 1)); assertEquals(15, scoreForKast("femere", 5, 2, 5, 5, 1)); public void seksereSkalGiAntall() throws Exception { assertEquals(0, scoreForKast("seksere", 1, 2, 2, 2, 1)); assertEquals(12, scoreForKast("seksere", 1, 2, 6, 6, 1)); assertEquals(18, scoreForKast("seksere", 6, 2, 6, 6, 1)); public void fulltHus() throws Exception { assertEquals(0, scoreForKast("fullt_hus", 1, 2, 3, 4, 5)); assertEquals(11, scoreForKast("fullt_hus", 1, 3, 3, 1, 3)); assertEquals(28, scoreForKast("fullt_hus", 5, 6, 6, 5, 6)); }
© Steria En test (vel... tre, public void femereSkalGiAntall() throws Exception { assertEquals(0, scoreForKast("femere", 1, 2, 2, 2, 1)); assertEquals(10, scoreForKast("femere", 1, 2, 5, 5, 1)); assertEquals(15, scoreForKast("femere", 5, 2, 5, 5, 1)); public void seksereSkalGiAntall() throws Exception { assertEquals(0, scoreForKast("seksere", 1, 2, 2, 2, 1)); assertEquals(12, scoreForKast("seksere", 1, 2, 6, 6, 1)); assertEquals(18, scoreForKast("seksere", 6, 2, 6, 6, 1)); public void fulltHus() throws Exception { assertEquals(0, scoreForKast("fullt_hus", 1, 2, 3, 4, 5)); assertEquals(11, scoreForKast("fullt_hus", 1, 3, 3, 1, 3)); assertEquals(28, scoreForKast("fullt_hus", 5, 6, 6, 5, 6)); }
© Steria | 29/06/2014Presentation titlep5 © Steria Agenda (skjult) Vekker: Hvorfor oppfører folk seg rart under fullmåne? Appertiff: Eksempel – test av yatzy poenggiving Bakgrunn: Johannes fra Steria. Nedgangstid? Ingen endringer. Søkt om sommerjobb? Svar i mars. Ønsketenking Hvilke foredeler har vi ved å skrive en test først `Hvilke fordeler har vi ved å beskrive besvarelsen først Agenda Krav som test TDD – demo Yatzy: Har énere, toere, treere. Trenger par, hus Konklusjon: Hvordan gjøre det bra på eksamen?
Hva var egentlig spørsmålet? Johannes Brodwall Chief Scientist, Steria
Hva er krav?
© Steria | 29/06/2014Presentation titlep8 © Steria ”Hvorfor skal kunden ha noe løst?”
© Steria | 29/06/2014Presentation titlep9 © Steria Behovsforståelse
© Steria | 29/06/2014Presentation titlep10 © Steria ”Hva skal løse når?”
© Steria | 29/06/2014Presentation titlep11 © Steria Planlegging
© Steria | 29/06/2014Presentation titlep12 © Steria ”Hvordan skal systemet løse hver enkelt krav?”
© Steria | 29/06/2014Presentation titlep13 © Steria Kravspesifikasjon
Eksempel: Signering
© Steria | 29/06/2014Presentation titlep15 © Steria Utvikler Produkteier Tester
© Steria | 29/06/2014Presentation titlep16 © Steria Utvikler Produkteier Tester Som en betaler, Ønsker jeg å signere mine oppdrag, Slik at ingen kan utgi seg for å være meg
© Steria | 29/06/2014Presentation titlep17 © Steria Utvikler Produkteier Tester Hva med både ok signerte og feilsignerte oppdrag i en fil?
© Steria | 29/06/2014Presentation titlep18 © Steria Utvikler Produkteier Tester Ummm (hjelp?)
© Steria
| 29/06/2014Presentation titlep20 © Steria Utvikler Produkteier Tester Gitt at en fil med oppdrag 1 og 2 Og oppdrag 1 er korrekt signert Og oppdrag 2 er ikke er korrekt signert Når filen valideres Så skal oppdrag 1 behandles normalt Og kunden skal motta en kvittering med teksten ”oppdrag 2 avvist”
© Steria FitNesse eksempel #1
© Steria FitNesse eksempel #1
© Steria | 29/06/2014Presentation titlep23 © Steria Utvikler Produkteier Tester Gitt at.... Når.... Så... Cucumber (rspec)
Et faktisk eksempel til
© Steria Fra mitt nåværende prosjekt: ”Ta arbeidsoppgave” Gitt jeg går til arbeidslistebilde ”teamets arbeidsliste” Og jeg velger oppgaven med ”Fødselsnummer” lik ” ” Og jeg trykker på ”Plukk oppgave” Når jeg går til arbeidslistebilde ”min arbeidsliste” Så skal oppgavelisten inneholde 1 oppgave Og oppgavens ”Fødselsnummer” skal være ” ”
© Steria Fra mitt nåværende prosjekt: ”Ta arbeidsoppgave” Gitt jeg går til arbeidslistebilde ”teamets arbeidsliste” Og jeg velger oppgaven med ”Fødselsnummer” lik ” ” Og jeg trykker på ”Plukk oppgave” Når jeg går til arbeidslistebilde ”min arbeidsliste” Så skal oppgavelisten inneholde 1 oppgave Og oppgavens ”Fødselsnummer” skal være ” ”
Eksempel: Yatzy
© Steria | 29/06/2014Presentation titlep28 © Steria Utvikler Produkteier Tester Fullt hus skal gi 25 poeng
© Steria
| 29/06/2014Presentation titlep30 © Steria Utvikler Produkteier Tester Fullt hus skal gi 25 poeng
© Steria | 29/06/2014Presentation titlep31 © Steria Utvikler Produkteier Tester Regnes det som fullt hus om fem dice har samme pipcount
© Steria | 29/06/2014Presentation titlep32 © Steria Utvikler Produkteier Tester WTF?!?
© Steria | 29/06/2014Presentation titlep33 © Steria Utvikler Produkteier Tester For eksempel fem 4-ere er ikke fullt hus Ok!
© Steria
Utviklers tester
Gjenspeiler funksjonelle tester
HUSKELAPP TIL JOHANNES: GÅ TIL ECLIPSE NÅ
Gode enhetstester er også krav
© Steria JUnit eksempel #3: public void shouldRetrieveSameInstanceForSameKey() throws Exception { Category inserted = new Category("A"); Serializable id = repository.insert(inserted); repository.flushChanges(); Category retrieved1 = repository.retrieve(Category.class, id); Category retrieved2 = repository.retrieve(Category.class, id); Category retrieved3 = repository.find(Category.class).iterator().next(); retrieved1.setCategoryName("Z"); assertEquals(retrieved1.getCategoryName(), retrieved2.getCategoryName()); assertEquals(retrieved1.getCategoryName(), retrieved3.getCategoryName()); }
© public void shouldRetrieveSameInstanceForSameKey() throws Exception { Category inserted = new Category("A"); Serializable id = repository.insert(inserted); repository.flushChanges(); Category retrieved1 = repository.retrieve(Category.class, id); Category retrieved2 = repository.retrieve(Category.class, id); Category retrieved3 = repository.find(Category.class).iterator().next(); retrieved1.setCategoryName("Z"); assertEquals(retrieved1.getCategoryName(), retrieved2.getCategoryName()); assertEquals(retrieved1.getCategoryName(), retrieved3.getCategoryName()); } JUnit eksempel #3: Repository When I change one instance Then the others should be updated, too Given a database with one category Given I retrieve this category several times
© Steria JUnit eksempel #3: public void uncommittedInsertsShouldBeInvisibleForOtherThreads() { repository.beginTransaction(); Category category = new Category("A"); repository.insert(category); repository.flushChanges(); assertNull(retrieveInNewThread(Category.class, category.getId())); repository.commit(); assertEquals(category, retrieveInNewThread(Category.class, category.getId())); }
© Steria JUnit eksempel #3: public void uncommittedInsertsShouldBeInvisibleForOtherThreads() { repository.beginTransaction(); Category category = new Category("A"); repository.insert(category); repository.flushChanges(); assertNull(retrieveInNewThread(Category.class, category.getId())); repository.commit(); assertEquals(category, retrieveInNewThread(Category.class, category.getId())); } Given I insert a new category while in a transaction When I retrieve the category from another thread Then I should not be able to see it When I commit the transaction When I retrieve the category from another thread Then I should be able to see it
© Steria JUnit eksempel #4: public void listProductsPageShouldShowAll() throws Exception { Product product1 = new Product(uniqueName("product"), 12300); Product product2 = new Product(uniqueName("product"), 300); repository.insertAll(product1, product2); repository.flushChanges(); tester.beginAt("/products/"); tester.assertTextInElement("products", product1.getProductName()); tester.assertTextInElement("products", product2.getProductName()); }
© Steria JUnit eksempel #4: public void listProductsPageShouldShowAll() throws Exception { Product product1 = new Product(uniqueName("product"), 12300); Product product2 = new Product(uniqueName("product"), 300); repository.insertAll(product1, product2); repository.flushChanges(); tester.beginAt("/products/"); tester.assertTextInElement("products", product1.getProductName()); tester.assertTextInElement("products", product2.getProductName()); } Then I should see both products Given two products with unique names in the database When I go to the /products/ web page
© Steria JUnit eksempel #5: Husk negative public void priceMustBeNumeric() throws Exception { String oldName = uniqueName("product"); int oldPrice = 1234; Product product = new Product(oldName, oldPrice); Serializable id = repository.insert(product); repository.flushChanges(); tester.beginAt("/products/" + id + "/edit.html"); tester.setTextField("productName", uniqueName("product")); tester.setTextField("price", "this is not a price!"); tester.submit(); tester.assertMatchInElement("errorExplaination", "[Pp]rice.*numeric"); Product stored = repository.retrieve(Product.class, id); assertEquals(oldPrice, stored.getPrice()); assertEquals(oldName, stored.getProductName()); }
© Steria JUnit eksempel #5: Husk negative public void priceMustBeNumeric() throws Exception { String oldName = uniqueName("product"); int oldPrice = 1234; Product product = new Product(oldName, oldPrice); Serializable id = repository.insert(product); repository.flushChanges(); tester.beginAt("/products/" + id + "/edit.html"); tester.setTextField("productName", uniqueName("product")); tester.setTextField("price", "this is not a price!"); tester.submit(); tester.assertMatchInElement("errorExplaination", "[Pp]rice.*numeric"); Product stored = repository.retrieve(Product.class, id); assertEquals(oldPrice, stored.getPrice()); assertEquals(oldName, stored.getProductName()); } Then I should see an error message Given a product in the database When I go to the /products/ /edit web page And I go change the price to a negative value And I press submit And the product should be unchanged in the database
© Steria | 29/06/2014Presentation titlep47 © Steria Utvikler Gitt at.... Når.... Så...
Test først gir godt design
© Steria JUnit eksempel #1: Yatzy public void simpleCategoriesShouldBeSumOfMatchingDice() {... public void smallStrait() {... public void largeStrait() {... public void threeOfAKind() {... }
© Steria JUnit eksempel #1: Yatzy public void threeOfAKind() { assertEquals(0, scoreFor("three_of_a_kind", 1, 1, 2, 2, 3)); assertEquals(3, scoreFor("three_of_a_kind", 1, 1, 1, 2, 3)); assertEquals(6, scoreFor("three_of_a_kind", 2, 2, 2, 3, 3)); assertEquals(9, scoreFor("three_of_a_kind", 1, 1, 3, 3, 3)); }
© Steria JUnit eksempel #1: Yatzy public void fullHouse() { assertEquals(0, scoreFor("full_house", 1, 1, 2, 2, 3)); assertEquals(0, scoreFor("full_house", 1, 1, 1, 2, 3)); assertEquals(25, scoreFor("full_house", 1, 1, 1, 2, 2)); assertEquals(25, scoreFor("full_house", 1, 1, 2, 2, 2)); assertEquals(25, scoreFor("full_house", 5, 5, 6, 6, 6)); }
© Steria JUnit eksempel #1: Yatzy public void histogramShouldReturnFrequencyOfEachDie() { int[] roll = { 1, 1, 2, 3, 4 }; int[] histogram = new ScoreCard().histogram(roll); assertEquals(7, histogram.length); assertEquals(-1, histogram[0]); assertEquals(2, histogram[1]); assertEquals(1, histogram[2]); assertEquals(1, histogram[3]); assertEquals(1, histogram[4]); assertEquals(0, histogram[5]); assertEquals(0, histogram[6]);
© Steria JUnit eksempel #1: Yatzy histogram scoreCalculators.put("four_of_a_kind", new ScoreCalculator() public int calculate(int[] histogram) { for (int i=0; i<histogram.length; i++) { if (histogram[i] >= 4) return i*4; } return 0; } });
Hvordan gjøre det bra på eksamen
Kjenn fasiten?
Forstå spørsmålet
Andre typer tester
© Steria | 29/06/2014Presentation titlep59 © Steria Ron Jeffries Only test what you want to work
© Steria | 29/06/2014Presentation titlep60 © Steria Johannes Find the defect where it’s cheapest
© Steria
Todo
© Steria JUnit eksempel #2: Session og transaksjoner public interface Repository { Serializable insert(Object entity); T retrieve(Class entityType, Serializable id); void update(Object entity); Collection find(Class entityType); void delete(Object entity); void flushChanges(); }
© Steria JUnit eksempel #2: Session og transaksjoner shouldRetrieveSeparateButEqualsAfterSessionFlush() shouldRetrieveSameInstanceForSameKey() rollbackShouldUndoInsertsDeletesAndUpdates() uncommittedInsertsShouldBeInvisibleForOtherThreads() uncommitedDeletesShouldBeInvisibleForOtherThreads() uncommitedUpdatesShouldBeInvisibleForOtherThreads()
© Steria JUnit eksempel #2: Session og transaksjoner public void startSession() { sessionForThread.set( new NestedChangeSet(permanentStore)); } public void beginTransaction() { this.transactionForThread.set( new NestedChangeSet(permanentStore)); getSession().setParent( this.transactionForThread.get()); }
Repository design
© Steria Vedlikeholdbarhet