Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Introduzione al TDD

2,018 views

Published on

Introduzione al TDD con esempi e consigli.

  • Be the first to comment

Introduzione al TDD

  1. 1. Introduzione al Test Driven Development Andrea Francia http://www.andreafrancia.it
  2. 2. Contents Concepts Definition Example1: Parser Example2: Text To Speech
  3. 3. Concepts Test First Automate tests
  4. 4. What is a Automated Test?
  5. 5. Automated Test Lifecycle Giordano Scalzo: http://www.slideshare.net/giordano/tdd-iphonefordummies
  6. 6. Automated Test Lifecycle Giordano Scalzo: http://www.slideshare.net/giordano/tdd-iphonefordummies
  7. 7. Automated Test Lifecycle SUT: System Under Test Giordano Scalzo: http://www.slideshare.net/giordano/tdd-iphonefordummies
  8. 8. Automated Test Lifecycle SUT: System Under Test Giordano Scalzo: http://www.slideshare.net/giordano/tdd-iphonefordummies
  9. 9. Automated Test Lifecycle SUT: System Under Test Giordano Scalzo: http://www.slideshare.net/giordano/tdd-iphonefordummies
  10. 10. Example of a Manual Test: nextLine() public static void main(String[] args) { String text = "first linensecond line"; Scanner scanner = new Scanner(text); System.out.println(scanner.nextLine()); // prints "first line" System.out.println(scanner.nextLine()); // prints "second line” } Code:
  11. 11. assertEquals(expected, actual); PASS FAIL expected == actual yes no
  12. 12. Using JUnit @Test public void howNextLineWorks() throws IOException { String text = "first linensecond line"; Scanner scanner = new Scanner(text); assertEquals(”first line", scanner.nextLine()); assertEquals(”second line", scanner.nextLine()); } Code: Output:
  13. 13. What is Test Driven Development?
  14. 14. What is TDD? Test-driven development (TDD) is a software development process that relies on the repetition of a very short development cycle: Giordano Scalzo: http://www.slideshare.net/giordano/tdd-iphonefordummies Tim Ottinger:http://agileinaflash.blogspot.com/2009/02/red-green-refactor.html
  15. 15. RED first the developer writes a failing automated test case that defines a desired new behaviour (of the software),
  16. 16. GREEN then produces code to pass that test …
  17. 17. Refactor and finally refactors the new code to acceptable standards.
  18. 18. Example: Writing “df” Parser
  19. 19. The df output [andreafrancia@deneb Dropbox]$ df Filesystem 1K-blocks Used Available Use% Mounted on /dev/disk0s2 243862672 135971832 107634840 56% / /dev/disk0s1 243862672 135971832 107634840 56% /tmp /dev/disk1s2 243862672 135971832 107634840 56% /opt devfs 109 109 0 100% /dev Mount Points
  20. 20. The problem List all mount points
  21. 21. The Problem Write a method that extract the list of the mount points from the output of df.
  22. 22. First of all decompose the problem!
  23. 23. Decomposition Parse the output of “df” process … When there are no mounted volumes When there is only one volume mounted When there are many volumes When the a volume contains whitespaces
  24. 24. First Cycle Parse the output of “df” process When there are no volumes When there is only one volume When there are many volumes When the a volume contains whitespaces
  25. 25. @Test public void whenNoVolumes() { String input = "Filesystem 1024-blocks Used Available Capacity Mounted on”; List<String> result = parseDfOutput(input); assertEquals(emptyList(), result); }
  26. 26. @Test public void whenNoVolumes() { String input = "Filesystem 1024-blocks Used Available Capacity Mounted on”; List<String> result = parseDfOutput(input); assertEquals(emptyList(), result); } private List<String> parseDfOutput(String string) { return null; }
  27. 27. @Test public void whenNoVolumes() { String input = "Filesystem 1024-blocks Used Available Capacity Mounted on”; List<String> result = parseDfOutput(input); assertEquals(emptyList(), result); } private List<String> parseDfOutput(String string) { return emptyList(); }
  28. 28. No need for refactoring
  29. 29. Second Cycle Parse the output of “df” process When there are no volumes When there is only one volume When there are many volumes When the a volume contains whitespaces
  30. 30. @Test public void whenOneVolume() { List<String> result = parseDfOutput("" + "Filesystem 1024-blocks Used Available Capacity Mounted onn" + "/dev/disk0s2 243862672 135479924 108126748 56% /"); assertEquals(asList("/"), result); }
  31. 31. private List<String> parseDfOutput(String string) { return emptyList(); }
  32. 32. private List<String> parseDfOutput(String string) { List<String> result = new ArrayList<String>(); return result; }
  33. 33. private List<String> parseDfOutput(String input) { List<String> result = new ArrayList<String>(); Scanner scanner = new Scanner(input); scanner.nextLine(); // skip header if(scanner.hasNextLine()) { String line = scanner.nextLine(); Scanner scanner1 = new Scanner(line); scanner1.next(); // skip Filesystem scanner1.next(); // skip 1024-blocks scanner1.next(); // skip Used scanner1.next(); // skip Available scanner1.next(); // skip Capacity String mountPoint = scanner1.next(); result.add(mountPoint); } return result; }
  34. 34. private List<String> parseDfOutput(String input) { List<String> result = new ArrayList<String>(); Scanner lines = new Scanner(input); lines.nextLine(); // skip header if(lines.hasNextLine()) { String line = lines.nextLine(); Scanner values = new Scanner(line); values.next(); // skip Filesystem values.next(); // skip 1024-blocks values.next(); // skip Used values.next(); // skip Available values.next(); // skip Capacity String mountPoint = values.next(); result.add(mountPoint); } return result; }
  35. 35. private List<String> parseDfOutput(String input) { List<String> result = new ArrayList<String>(); Scanner lines = new Scanner(input); lines.nextLine(); // skip header if(lines.hasNextLine()) { result.add(parseMountPoint(lines.nextLine())); } return result; } private String parseMountPoint(String line) { Scanner values = new Scanner(line); values.next(); // skip Filesystem values.next(); // skip 1024-blocks values.next(); // skip Used values.next(); // skip Available values.next(); // skip Capacity String mountPoint = values.next(); return mountPoint; }
  36. 36. Third Cycle Parse the output of “df” process When there are no volumes When there is only one volume When there are many volumes When the a volume contains whitespaces
  37. 37. @Test public void whenMultipleVolume() { List<String> result = parseDfOutput("" + "Filesystem 1024-blocks Used Available Capacity Mounted onn" + "/dev/disk0s2 243862672 135479924 108126748 56% /n" + "/dev/disk0s2 243862672 135479924 108126748 56% /media/diskn" + "/dev/disk0s2 243862672 135479924 108126748 56% /tmpn"); assertEquals(asList("/", "/media/disk", "/tmp"), result); }
  38. 38. @Test public void whenMultipleVolume() { List<String> result = parseDfOutput("" + "Filesystem 1024-blocks Used Available Capacity Mounted onn" + "/dev/disk0s2 243862672 135479924 108126748 56% /n" + "/dev/disk0s2 243862672 135479924 108126748 56% /media/diskn" + "/dev/disk0s2 243862672 135479924 108126748 56% /tmpn"); assertEquals(asList("/", "/media/disk", "/tmp"), result); }
  39. 39. private List<String> parseDfOutput(String input) { List<String> result = new ArrayList<String>(); Scanner lines = new Scanner(input); lines.nextLine(); // skip header if(lines.hasNextLine()) { String line = lines.nextLine(); String mountPoint = parseMountPoint(line); result.add(mountPoint); } return result; }
  40. 40. private List<String> parseDfOutput(String input) { List<String> result = new ArrayList<String>(); Scanner lines = new Scanner(input); lines.nextLine(); // skip header while(lines.hasNextLine()) { String line = lines.nextLine(); String mountPoint = parseMountPoint(line); result.add(mountPoint); } return result; }
  41. 41. TDD Rules
  42. 42. TDD Rules Test First Test for All Features Remove all duplication (always)
  43. 43. Some hints Keep tests running and passing Keeps test small Don’t mix phases (Red, Green, Refactor) Don’t mix unit tests with integration tests Test only one feature per test
  44. 44. Examples from my last work
  45. 45. Regole applicate Ogni feature deve essere sviluppata secondo il TDD Partire dai test di accettazione Ritardare le decisioni di design all’ultimo momento responsabile Applicare un principio di design solo dopo aver avuto la prova che sia utile in quel specifico caso
  46. 46. Prima feature: produrre testo pronunciabile
  47. 47. Test di accettazione public class HoroscopeTest { @Test public void userListenOroscope() { Horoscope horoscope = new Horoscope(); horoscope.saveDivination("22-GIU-10", "Ariete", "Sarai molto fortunato."); String result = horoscope.GET("/horoscope/ariete.txt"); assertEquals("22 giugno 2010: Ariete, Sarai molto fortunato.”, result); }
  48. 48. No test  No code Quando scrivo il codice di produzione scrivo il minimo necessario a far passare il test Se il minimo non mi convince (è troppo stupido), vuol dire che manca una specifica funzionale  cioè manca un test. Prima di scrivere una qualsiasi riga di codice in più aggiungo un test che la richieda.
  49. 49. @Test public void shouldStoreDivinationsForMultipleSigns() { Horoscope horoscope = new Horoscope(); horoscope.saveDivination("22-GIU-10", "Ariete", "for ariete"); horoscope.saveDivination("22-GIU-10", "Toro", "for toro"); assertEquals("22 giugno 2010: Ariete, for ariete", horoscope.GET("/horoscope/ariete.txt")); assertEquals("22 giugno 2010: Toro, for toro", horoscope.GET("/horoscope/toro.txt")); }
  50. 50. Cerco di non anticipare il design Prima di affrontare lo sviluppo faccio una veloce sessione di design Non implemento nessuna decisione fino a che non si rende necessaria E.g. anche servirà un DAO per adesso salvo tutto in RAM
  51. 51. Seconda Feature: oroscopo ascoltabile
  52. 52. @Test public void howToCreateMp3() { Horoscope horoscope = new Horoscope( aFakeSyntetizerWhichReturns( aMp3Stream())); horoscope.saveDivination("22-GIU-10", "Ariete", "divination"); assertThat(horoscope.GET( "/horoscope/ariete.mp3").asByteArray(), is(equalTo(aMp3Stream()))); }
  53. 53. Resource Ora il GET restituisce una Resource  public Resource GET(String path) {...} Il client decide quale rappresentazione usare: horoscope.GET("/horoscope/ariete/divination.txt").asString()); horoscope.GET("/horoscope/ariete/divination.mp3").asByteArray();
  54. 54. Terza feature: la persistenza
  55. 55. Stato delle cose Al momento tutto viene persistito in memoria (in una HashMap) Non esiste ancora un oggetto DAO, tutto viene fatto dall’unica class Horoscope
  56. 56. Estrazione del comportamento public class MemoryDivinationRepo { Divination lastDivinationForSign(String sign); void saveDivinationFromPronounce(String sign, String pronounce); }; public interface Divination { String asText(); byte[] asMp3(); };
  57. 57. Estrazione dell’interfaccia public class MemoryDivinationRepo implements DivinationRepo {...} public interface DivinationRepo { Divination lastDivinationForSign(String sign); void saveDivinationFromPronounce(String sign, String pronounce); };
  58. 58. Caratterizzazione del comportamento L’interfaccia è una minima parte del contratto, la parte più importante è il comportamento che l’oggetto dovrebbe avere. Il comportamento lo estraggo con dei test di caratterizzazione
  59. 59. Caratterizzazione di MemoryDivinationRepo public class MemoryDivinationRepoTest { @Test public void shouldStoreDivinationPronounceForASign() {...} @Test public void shouldReplyWithAPronouncedMp3() {...} @Test public void shouldStoreDivinationPronounceForMultipleSigns() {...} @Test public void shouldOverrideDivinationPronounce() {...} }
  60. 60. Thanks Andrea Francia www.andreafrancia.it blog.andreafrancia.it andrea@andreafrancia.it
  61. 61. Extra slides
  62. 62. Example of an Automated Test @Test public void shouldParsePath() { String content = "[Trash Info]n" + "Path=/home/andrea/foo.txtn" + "DeletionDate=2010-08-23T12:59:14n"; String path = Parser.parsePath(content); assertEquals("/home/andrea/foo.txt”, path); }
  63. 63. Testing Frameworks http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks •PHPUnit •SimpleTest •Google C++ Testing Framework •CppUnitLite •CppUnit •JUnit •TestNG •PyUnit •Nose

×