SlideShare uma empresa Scribd logo
1 de 41
Bessere Tests mit JUnit 4.x
Marc Philipp
24. Juni 2010
Über JUnit


                Kent Beck:
                A programmer-oriented testing
                framework for Java.

                David Saff:
                JUnit is the intersection of all
                possible useful Java test
                frameworks, not their union.

                Nicht nur für Unit Tests!



24. Juni 2010                                      2
Warum ein Vortrag über JUnit?



        Jeder kennt JUnit.
        Wirklich?
        Jeder meint, JUnit zu kennen.
        Ich meinte es auch.
        Seit Version 4.0 hat sich einiges getan!




24. Juni 2010                                      3
Neue Features seit Version 4.0


        Matchers                        Rules



                        JUnit 4.8.2



         Theories                     Categories



24. Juni 2010                                      4
Matchers




René Magritte, Untitled              5
Neue Assertion: assertThat(...)


        Neue Assert-Methoden:
        <T> void assertThat(T actual, Matcher<T> matcher)
        <T> void assertThat(String reason, T actual, Matcher<T> matcher)


        Parameter:
         reason Zusätzliche Beschreibung für den Fehlerfall (optional)
          actual Tatsächlicher Wert
        matcher Hamcrest-Matcher überprüft tatsächlichen Wert




24. Juni 2010                                                              6
Bessere Lesbarkeit

 import static org.hamcrest.CoreMatchers.is;

 public class BetterReadability {

     @Test public void withoutMatchers() {
        assertEquals(2, 1 + 1);
     }

     @Test public void withMatchers() {
        assertThat(1 + 1, is(2));
     }
 }



        Reihenfolge stimmt
        Häufig besser lesbar als herkömmliche Assertions


24. Juni 2010                                             7
Matcher kombinieren




 Matcher lassen sich einfach kombinieren:
   assertThat(1 + 1, is(not(3)));
   assertThat(1 + 1, both(greaterThan(1)).and(lessThan(3)));




24. Juni 2010                                                  8
Aussagekräftige Fehlermeldungen
 Herkömmliche Zusicherung ohne Beschreibung
   assertFalse(asList(1, 2, 3).contains(2));


 Ergebnis:
 AssertionError: at de.andrena.junit...




 Neue Zusicherung mit Matcher
   assertThat(asList(1, 2, 3), not(hasItem(2)));


 Ergebnis:
 AssertionError:
 Expected: not a collection containing <2>
      got: <[1, 2, 3]>



24. Juni 2010                                      9
Vordefinierte Matcher


        Vielzahl vordefinierter Matcher:
              Core is, not, allOf, anyOf, nullValue, . . .
            Strings containsString, startsWith, endsWith, . . .
        Collections hasItem, hasItems, isIn, empty, hasSize, . . .
        Bei JUnit ist nur ein kleiner Teil mit dabei:
                org.hamcrest.CoreMatchers
                org.junit.matchers.JUnitMatchers
        Hamcrest bietet weitere Matcher (hamcrest-all.jar).
        Darüber hinaus lassen sich eigene Matcher definieren.




24. Juni 2010                                                        10
Ein eigener Matcher
Implementierung


  public class IsEmptyCollection extends TypeSafeMatcher<Collection<?>> {

      @Override protected boolean matchesSafely(Collection<?> collection) {
         return collection.isEmpty();
      }

      @Override public void describeTo(Description description) {
         description.appendText("empty");
      }

      @Factory public static Matcher<Collection<?>> empty() {
         return new IsEmptyCollection();
      }
  }




 24. Juni 2010                                                                11
Ein eigener Matcher
Benutzung




  public class CollectionMatchersTest {

      @Test public void isEmpty() {
         TreeSet<String> set = new TreeSet<String>();
         assertThat(set, new IsEmptyCollection());   //   direkter Aufruf
         assertThat(set, IsEmptyCollection.empty()); //   über @Factory-Methode
         assertThat(set, empty());                   //   mit statischem Import
         assertThat(set, is(empty()));               //   syntactic sugar
      }
  }




 24. Juni 2010                                                                    12
Viele Matcher – Viele Klassen


 Problem
        Vielzahl von Klassen mit zu importierenden statischen Methoden
        Manuelle Konfiguration der IDE notwendig
        . . . bei allen Entwicklern

 Lösung
 Generierung einer eigenen Matcher-Bibliothek




24. Juni 2010                                                            13
Generierung einer Matcher-Bibliothek
   1. Konfiguration in XML
        <matchers>
           <factory class="org.hamcrest.core.Is"/>
           <factory class="de.andrena.junit.hamcrest.IsEmptyCollection"/>
        </matchers>


   2. Aufruf von org.hamcrest.generator.config.XmlConfigurator
   3. Alle mit @Factory annotierten Methoden werden in einer
      generierten Klasse zusammengefasst:
        public class Matchers {
           public static <T> Matcher<? super T> is(T param1) {
              return org.hamcrest.core.Is.is(param1);
           }
           /* ... */
           public static Matcher<Collection<?>> empty() {
              return de.andrena.junit.hamcrest.IsEmptyCollection.empty();
           }
        }


24. Juni 2010                                                               14
Fazit: Matchers

        Assertions lassen sich oft eleganter formulieren
        Manchmal sind die alten Assertion-Methoden klarer

 Problem
 Javas Typsystem macht einem oft einen Strich durch die Rechnung
        Boxing notwendig bei primitiven Typen
        assertThat(1 + 1, is(2))


        Mangelnde Typinferenz
        assertThat(new TreeSet<String>(), Matchers.<String>empty());




24. Juni 2010                                                          15
Theories




Wassily Kandinsky, Composition VIII              16
Parametrisierte Tests


        Seit JUnit 4.0 gibt es den Parameterized Test Runner.
        Ermöglicht Parametrisierung von Testklassen über Konstruktor
        Argumente werden in einer statischen Methode angegeben:
                @Parameters-Annotation
                Rückgabetyp: List<Object[]>
        Für jedes Paar von Testmethode und Argument wird eine Instanz
        der Testklasse angelegt und die Testmethode ausgeführt.
        Nützlich, wenn Berechnung mit vielen Eingabeparametern getestet
        werden soll.




24. Juni 2010                                                             17
Parametrisierte Tests
Beispiel: Fibonacci-Zahlen
  @RunWith(Parameterized.class)
  public class FibonacciParameterizedTest {

      @Parameters public static List<Object[]> data() {
         return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
               { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
      }

      private final int input, expected;

      public FibonacciParameterizedTest(int input, int expected) {
         this.input = input;
         this.expected = expected;
      }

      @Test public void test() {
         assertEquals(expected, Fibonacci.compute(input));
      }
  }


 24. Juni 2010                                                                 18
Theories



        Neu seit Version 4.4
        Parametrisierte Testmethode mit Vorbedingungen (Assumptions)
                assumeThat()
                assumeTrue()
                assumeNotNull()

        @Theory    statt @Test
        Input für Testmethoden über @DataPoint(s)-Annotation




24. Juni 2010                                                          19
Theories
Beispiel: Fibonacci-Zahlen

  import static de.andrena.junit.fibonacci.Fibonacci.compute;

  @RunWith(Theories.class)
  public class FibonacciTheories {

      @DataPoints public static int[] VALUES = { 0, 1, 2, 3, 4, 5, 6 };

      @Theory public void seeds(int n) {        //   F (0) = 0, F (1) = 1
         assumeTrue(n <= 1);
         assertEquals(n, compute(n));
      }

      @Theory public void recurrence(int n) { // F (n) = F (n − 1) + F (n   − 2) für n > 1
         assumeTrue(n > 1);
         assertEquals(compute(n - 1) + compute(n - 2), compute(n));
      }
  }



 24. Juni 2010                                                                           20
Theories
Beispiel: Verschiedene @DataPoints

  @RunWith(Theories.class)
  public class DifferentDataPoints {

      @DataPoint public static String A = "a";
      @DataPoint public static String B = "b";
      @DataPoints public static int[] NUMBERS = { 1, 2, 3 };

      @Theory public void theory1(String string) {
         /* ("a"), ("b") */
      }
      @Theory public void theory2(int number) {
         /* (1), (2), (3) */
      }
      @Theory public void theory3(String string, int number) {
         /* ("a", 1), ("a", 2), ("a", 3), ("b", 1), ("b", 2), ("b", 3) */
      }
  }



 24. Juni 2010                                                              21
Parameterized Tests vs. Theories


        Definition von @DataPoints ist flexibler
                Konstanten oder Methoden
                Beliebig viele
                Verschiedene Typen
        Parametrisierung der Testmethoden
                Kein Boilerplate-Code (Konstruktor + Instanzvariablen)
                Verschiedene Parametertypen möglich
        Theories     können alles, was Parameterized auch kann, aber mehr!




24. Juni 2010                                                            22
Herkömmliche Tests vs. Theories


        Herkömmliche Tests benutzen Beispiele:
                Überprüfung des Verhaltens unter ausgewählten Eingaben
                Beispiele sind (hoffentlich) charakteristisch
        Eine Theory verallgemeinert eine Menge von Tests:
                Vorbedingung wird explizit angegeben
                Sollte für alle Eingaben gelten, die Vorbedingungen erfüllen
        Eingabewerte können explizit angegeben werden oder automatisch
        erzeugt werden




24. Juni 2010                                                                  23
Rules




René Magritte, Golconda           24
Was ist eine Rule?


 Erweiterungsmechanismus für Ablauf der Testmethoden
 Beispiele:
        Ausführung eigenen Codes vor bzw. nach jeder Testmethode
        Behandlung fehlgeschlagener Tests
        Überprüfung zusätzlicher Kriterien nach einem Tests
        ...




24. Juni 2010                                                      25
Beispiel: TemporaryFolder
Ohne Benutzung einer Rule

  public class TemporaryFolderWithoutRule {
     private File folder;

     @Before public void createTemporaryFolder() throws Exception {
        folder = File.createTempFile("myFolder", "");
        folder.delete();
        folder.mkdir();
     }

     @Test public void test() throws Exception {
        File file = new File(folder, "test.txt");
        file.createNewFile();
        assertTrue(file.exists());
     }

     @After public void deleteTemporaryFolder() {
        recursivelyDelete(folder); // passt nicht mehr auf die Folie...
     }



 24. Juni 2010                                                            26
Beispiel: TemporaryFolder
Unter Verwendung einer Rule




  public class TemporaryFolderWithRule {

      @Rule public TemporaryFolder folder = new TemporaryFolder();

      @Test public void test() throws Exception {
         File file = folder.newFile("test.txt");
         assertTrue(file.exists());
      }

  }




 24. Juni 2010                                                       27
Was ist eine Rule?


 Erweiterungsmechanismus für Ablauf der Testmethoden
 Beispiele:
        Ausführung eigenen Codes vor bzw. nach jeder Testmethode
        Behandlung fehlgeschlagener Tests
        Überprüfung zusätzlicher Kriterien nach einem Tests
        ...




24. Juni 2010                                                      28
Beispiel: ExpectedException
Ohne Benutzung einer Rule

  public class ExpectedExceptionWithoutRule {

      int[] threeNumbers = { 1, 2, 3 };

      @Test(expected = ArrayIndexOutOfBoundsException.class)
      public void exception() {
         threeNumbers[3] = 4;
      }

      @Test public void exceptionWithMessage() {
         try {
            threeNumbers[3] = 4;
            fail("ArrayIndexOutOfBoundsException expected");
         } catch (ArrayIndexOutOfBoundsException expected) {
            assertEquals("3", expected.getMessage());
         }
      }
  }



 24. Juni 2010                                                 29
Beispiel: ExpectedException
Unter Verwendung einer Rule

  public class ExpectedExceptionWithRule {

      int[] threeNumbers = { 1, 2, 3 };

      @Rule public ExpectedException thrown = ExpectedException.none();

      @Test public void exception() {
         thrown.expect(ArrayIndexOutOfBoundsException.class);
         threeNumbers[3] = 4;
      }

      @Test public void exceptionWithMessage() {
         thrown.expect(ArrayIndexOutOfBoundsException.class);
         thrown.expectMessage("3");
         threeNumbers[3] = 4;
      }
  }



 24. Juni 2010                                                            30
Weitere vordefinierte Rules


 ErrorCollector
 Sammelt fehlgeschlagene Assertions innerhalb einer Testmethode und
 gibt am Ende eine Liste der Fehlschläge aus.

 TestName
 Merkt sich Namen der aktuell ausgeführten Testmethode und stellt ihn
 auf Anfrage zur Verfügung.

 Timeout
 Wendet gleichen Timeout auf alle Testmethoden einer Klasse an.




24. Juni 2010                                                           31
Schreib deine eigenen Regeln!




24. Juni 2010                   32
Eine eigene Regel
Implementierung
  public class SystemProperty extends ExternalResource {
     private final String key, value;
     private String oldValue;
     public SystemProperty(String key, String value) {
        this.key = key;
        this.value = value;
     }
     @Override protected void before() {
        oldValue = System.getProperty(key);
        System.setProperty(key, value);
     }
     @Override protected void after() {
        if (oldValue == null) {
           System.getProperties().remove(key);
        } else {
           System.setProperty(key, oldValue);
        }
     }
  }


 24. Juni 2010                                             33
Eine eigene Regel
Benutzung




  public class SomeTestUsingSystemProperty {

      private static final String VALUE = "someValue";
      private static final String KEY = "someKey";

      @Rule public SystemProperty systemProperty = new SystemProperty(KEY, VALUE);

      @Test public void test() {
         assertThat(System.getProperty(KEY), is(VALUE));
      }
  }




 24. Juni 2010                                                                       34
Vorteile von Regeln


 Wiederverwendbarkeit
 Ermöglichen häufig benötigten Code auszulagern.

 Kombinierbarkeit
 Beliebig viele Regeln in einem Test verwendbar

 Delegation statt Vererbung
 Helfen Testklassenhierarchien zu vermeiden!

 Erweiterbarkeit
 Eigene Regeln schreiben ist einfach.



24. Juni 2010                                     35
Categories




Piet Mondrian, Composition with Gray and Light Brown   36
Tests in Kategorien einteilen
        Kategorie ist Klasse oder Interface:
        public interface Slow {}


        Einzelner Test:
         @Category(Slow.class)
         @Test
         public void test() {}


        Alle Tests einer Klasse:
        @Category(Slow.class)
        public class B {
           @Test
           public void c() {}
        }




24. Juni 2010                                  37
Tests in bestimmten Kategorien ausführen
        Herkömmliche Test-Suite:
        @RunWith(Suite.class)
        @SuiteClasses( { A.class, B.class })
        public class AllTests {}


        Alle Tests in der Kategorie Slow:
        @RunWith(Categories.class)
        @IncludeCategory(Slow.class)
        public class AllSlowTests extends AllTests {}


        Alle anderen Tests:
        @RunWith(Categories.class)
        @ExcludeCategory(Slow.class)
        public class AllFastTests extends AllTests {}




24. Juni 2010                                           38
Ausblick




Quint Buchholz, Mann auf einer Leiter              39
Was jetzt?



        Aktualisierung auf neue Version ist einfach
        Alte Tests funktionieren weiterhin
        Neue Tests profitieren von neuen Features
        Alte Tests können nach und nach vereinfacht werden
        Ausprobieren!




24. Juni 2010                                                40
Ausprobieren!
 http://www.junit.org/


    Grau is alle Theorie – entscheidend is auf’m Platz
                                                         – Adi Preissler




                        Vielen Dank!
     Mail marc@andrena.de
 Twitter marcphilipp
    Blog http://marcphilipp.tumblr.com/
24. Juni 2010                                                              41

Mais conteúdo relacionado

Destaque

Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTExpeed Software
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsPixeldarts
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthThinkNow
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfmarketingartwork
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Applitools
 

Destaque (20)

Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPT
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
 

Bessere Tests mit JUnit 4.x

  • 1. Bessere Tests mit JUnit 4.x Marc Philipp 24. Juni 2010
  • 2. Über JUnit Kent Beck: A programmer-oriented testing framework for Java. David Saff: JUnit is the intersection of all possible useful Java test frameworks, not their union. Nicht nur für Unit Tests! 24. Juni 2010 2
  • 3. Warum ein Vortrag über JUnit? Jeder kennt JUnit. Wirklich? Jeder meint, JUnit zu kennen. Ich meinte es auch. Seit Version 4.0 hat sich einiges getan! 24. Juni 2010 3
  • 4. Neue Features seit Version 4.0 Matchers Rules JUnit 4.8.2 Theories Categories 24. Juni 2010 4
  • 6. Neue Assertion: assertThat(...) Neue Assert-Methoden: <T> void assertThat(T actual, Matcher<T> matcher) <T> void assertThat(String reason, T actual, Matcher<T> matcher) Parameter: reason Zusätzliche Beschreibung für den Fehlerfall (optional) actual Tatsächlicher Wert matcher Hamcrest-Matcher überprüft tatsächlichen Wert 24. Juni 2010 6
  • 7. Bessere Lesbarkeit import static org.hamcrest.CoreMatchers.is; public class BetterReadability { @Test public void withoutMatchers() { assertEquals(2, 1 + 1); } @Test public void withMatchers() { assertThat(1 + 1, is(2)); } } Reihenfolge stimmt Häufig besser lesbar als herkömmliche Assertions 24. Juni 2010 7
  • 8. Matcher kombinieren Matcher lassen sich einfach kombinieren: assertThat(1 + 1, is(not(3))); assertThat(1 + 1, both(greaterThan(1)).and(lessThan(3))); 24. Juni 2010 8
  • 9. Aussagekräftige Fehlermeldungen Herkömmliche Zusicherung ohne Beschreibung assertFalse(asList(1, 2, 3).contains(2)); Ergebnis: AssertionError: at de.andrena.junit... Neue Zusicherung mit Matcher assertThat(asList(1, 2, 3), not(hasItem(2))); Ergebnis: AssertionError: Expected: not a collection containing <2> got: <[1, 2, 3]> 24. Juni 2010 9
  • 10. Vordefinierte Matcher Vielzahl vordefinierter Matcher: Core is, not, allOf, anyOf, nullValue, . . . Strings containsString, startsWith, endsWith, . . . Collections hasItem, hasItems, isIn, empty, hasSize, . . . Bei JUnit ist nur ein kleiner Teil mit dabei: org.hamcrest.CoreMatchers org.junit.matchers.JUnitMatchers Hamcrest bietet weitere Matcher (hamcrest-all.jar). Darüber hinaus lassen sich eigene Matcher definieren. 24. Juni 2010 10
  • 11. Ein eigener Matcher Implementierung public class IsEmptyCollection extends TypeSafeMatcher<Collection<?>> { @Override protected boolean matchesSafely(Collection<?> collection) { return collection.isEmpty(); } @Override public void describeTo(Description description) { description.appendText("empty"); } @Factory public static Matcher<Collection<?>> empty() { return new IsEmptyCollection(); } } 24. Juni 2010 11
  • 12. Ein eigener Matcher Benutzung public class CollectionMatchersTest { @Test public void isEmpty() { TreeSet<String> set = new TreeSet<String>(); assertThat(set, new IsEmptyCollection()); // direkter Aufruf assertThat(set, IsEmptyCollection.empty()); // über @Factory-Methode assertThat(set, empty()); // mit statischem Import assertThat(set, is(empty())); // syntactic sugar } } 24. Juni 2010 12
  • 13. Viele Matcher – Viele Klassen Problem Vielzahl von Klassen mit zu importierenden statischen Methoden Manuelle Konfiguration der IDE notwendig . . . bei allen Entwicklern Lösung Generierung einer eigenen Matcher-Bibliothek 24. Juni 2010 13
  • 14. Generierung einer Matcher-Bibliothek 1. Konfiguration in XML <matchers> <factory class="org.hamcrest.core.Is"/> <factory class="de.andrena.junit.hamcrest.IsEmptyCollection"/> </matchers> 2. Aufruf von org.hamcrest.generator.config.XmlConfigurator 3. Alle mit @Factory annotierten Methoden werden in einer generierten Klasse zusammengefasst: public class Matchers { public static <T> Matcher<? super T> is(T param1) { return org.hamcrest.core.Is.is(param1); } /* ... */ public static Matcher<Collection<?>> empty() { return de.andrena.junit.hamcrest.IsEmptyCollection.empty(); } } 24. Juni 2010 14
  • 15. Fazit: Matchers Assertions lassen sich oft eleganter formulieren Manchmal sind die alten Assertion-Methoden klarer Problem Javas Typsystem macht einem oft einen Strich durch die Rechnung Boxing notwendig bei primitiven Typen assertThat(1 + 1, is(2)) Mangelnde Typinferenz assertThat(new TreeSet<String>(), Matchers.<String>empty()); 24. Juni 2010 15
  • 17. Parametrisierte Tests Seit JUnit 4.0 gibt es den Parameterized Test Runner. Ermöglicht Parametrisierung von Testklassen über Konstruktor Argumente werden in einer statischen Methode angegeben: @Parameters-Annotation Rückgabetyp: List<Object[]> Für jedes Paar von Testmethode und Argument wird eine Instanz der Testklasse angelegt und die Testmethode ausgeführt. Nützlich, wenn Berechnung mit vielen Eingabeparametern getestet werden soll. 24. Juni 2010 17
  • 18. Parametrisierte Tests Beispiel: Fibonacci-Zahlen @RunWith(Parameterized.class) public class FibonacciParameterizedTest { @Parameters public static List<Object[]> data() { return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } }); } private final int input, expected; public FibonacciParameterizedTest(int input, int expected) { this.input = input; this.expected = expected; } @Test public void test() { assertEquals(expected, Fibonacci.compute(input)); } } 24. Juni 2010 18
  • 19. Theories Neu seit Version 4.4 Parametrisierte Testmethode mit Vorbedingungen (Assumptions) assumeThat() assumeTrue() assumeNotNull() @Theory statt @Test Input für Testmethoden über @DataPoint(s)-Annotation 24. Juni 2010 19
  • 20. Theories Beispiel: Fibonacci-Zahlen import static de.andrena.junit.fibonacci.Fibonacci.compute; @RunWith(Theories.class) public class FibonacciTheories { @DataPoints public static int[] VALUES = { 0, 1, 2, 3, 4, 5, 6 }; @Theory public void seeds(int n) { // F (0) = 0, F (1) = 1 assumeTrue(n <= 1); assertEquals(n, compute(n)); } @Theory public void recurrence(int n) { // F (n) = F (n − 1) + F (n − 2) für n > 1 assumeTrue(n > 1); assertEquals(compute(n - 1) + compute(n - 2), compute(n)); } } 24. Juni 2010 20
  • 21. Theories Beispiel: Verschiedene @DataPoints @RunWith(Theories.class) public class DifferentDataPoints { @DataPoint public static String A = "a"; @DataPoint public static String B = "b"; @DataPoints public static int[] NUMBERS = { 1, 2, 3 }; @Theory public void theory1(String string) { /* ("a"), ("b") */ } @Theory public void theory2(int number) { /* (1), (2), (3) */ } @Theory public void theory3(String string, int number) { /* ("a", 1), ("a", 2), ("a", 3), ("b", 1), ("b", 2), ("b", 3) */ } } 24. Juni 2010 21
  • 22. Parameterized Tests vs. Theories Definition von @DataPoints ist flexibler Konstanten oder Methoden Beliebig viele Verschiedene Typen Parametrisierung der Testmethoden Kein Boilerplate-Code (Konstruktor + Instanzvariablen) Verschiedene Parametertypen möglich Theories können alles, was Parameterized auch kann, aber mehr! 24. Juni 2010 22
  • 23. Herkömmliche Tests vs. Theories Herkömmliche Tests benutzen Beispiele: Überprüfung des Verhaltens unter ausgewählten Eingaben Beispiele sind (hoffentlich) charakteristisch Eine Theory verallgemeinert eine Menge von Tests: Vorbedingung wird explizit angegeben Sollte für alle Eingaben gelten, die Vorbedingungen erfüllen Eingabewerte können explizit angegeben werden oder automatisch erzeugt werden 24. Juni 2010 23
  • 25. Was ist eine Rule? Erweiterungsmechanismus für Ablauf der Testmethoden Beispiele: Ausführung eigenen Codes vor bzw. nach jeder Testmethode Behandlung fehlgeschlagener Tests Überprüfung zusätzlicher Kriterien nach einem Tests ... 24. Juni 2010 25
  • 26. Beispiel: TemporaryFolder Ohne Benutzung einer Rule public class TemporaryFolderWithoutRule { private File folder; @Before public void createTemporaryFolder() throws Exception { folder = File.createTempFile("myFolder", ""); folder.delete(); folder.mkdir(); } @Test public void test() throws Exception { File file = new File(folder, "test.txt"); file.createNewFile(); assertTrue(file.exists()); } @After public void deleteTemporaryFolder() { recursivelyDelete(folder); // passt nicht mehr auf die Folie... } 24. Juni 2010 26
  • 27. Beispiel: TemporaryFolder Unter Verwendung einer Rule public class TemporaryFolderWithRule { @Rule public TemporaryFolder folder = new TemporaryFolder(); @Test public void test() throws Exception { File file = folder.newFile("test.txt"); assertTrue(file.exists()); } } 24. Juni 2010 27
  • 28. Was ist eine Rule? Erweiterungsmechanismus für Ablauf der Testmethoden Beispiele: Ausführung eigenen Codes vor bzw. nach jeder Testmethode Behandlung fehlgeschlagener Tests Überprüfung zusätzlicher Kriterien nach einem Tests ... 24. Juni 2010 28
  • 29. Beispiel: ExpectedException Ohne Benutzung einer Rule public class ExpectedExceptionWithoutRule { int[] threeNumbers = { 1, 2, 3 }; @Test(expected = ArrayIndexOutOfBoundsException.class) public void exception() { threeNumbers[3] = 4; } @Test public void exceptionWithMessage() { try { threeNumbers[3] = 4; fail("ArrayIndexOutOfBoundsException expected"); } catch (ArrayIndexOutOfBoundsException expected) { assertEquals("3", expected.getMessage()); } } } 24. Juni 2010 29
  • 30. Beispiel: ExpectedException Unter Verwendung einer Rule public class ExpectedExceptionWithRule { int[] threeNumbers = { 1, 2, 3 }; @Rule public ExpectedException thrown = ExpectedException.none(); @Test public void exception() { thrown.expect(ArrayIndexOutOfBoundsException.class); threeNumbers[3] = 4; } @Test public void exceptionWithMessage() { thrown.expect(ArrayIndexOutOfBoundsException.class); thrown.expectMessage("3"); threeNumbers[3] = 4; } } 24. Juni 2010 30
  • 31. Weitere vordefinierte Rules ErrorCollector Sammelt fehlgeschlagene Assertions innerhalb einer Testmethode und gibt am Ende eine Liste der Fehlschläge aus. TestName Merkt sich Namen der aktuell ausgeführten Testmethode und stellt ihn auf Anfrage zur Verfügung. Timeout Wendet gleichen Timeout auf alle Testmethoden einer Klasse an. 24. Juni 2010 31
  • 32. Schreib deine eigenen Regeln! 24. Juni 2010 32
  • 33. Eine eigene Regel Implementierung public class SystemProperty extends ExternalResource { private final String key, value; private String oldValue; public SystemProperty(String key, String value) { this.key = key; this.value = value; } @Override protected void before() { oldValue = System.getProperty(key); System.setProperty(key, value); } @Override protected void after() { if (oldValue == null) { System.getProperties().remove(key); } else { System.setProperty(key, oldValue); } } } 24. Juni 2010 33
  • 34. Eine eigene Regel Benutzung public class SomeTestUsingSystemProperty { private static final String VALUE = "someValue"; private static final String KEY = "someKey"; @Rule public SystemProperty systemProperty = new SystemProperty(KEY, VALUE); @Test public void test() { assertThat(System.getProperty(KEY), is(VALUE)); } } 24. Juni 2010 34
  • 35. Vorteile von Regeln Wiederverwendbarkeit Ermöglichen häufig benötigten Code auszulagern. Kombinierbarkeit Beliebig viele Regeln in einem Test verwendbar Delegation statt Vererbung Helfen Testklassenhierarchien zu vermeiden! Erweiterbarkeit Eigene Regeln schreiben ist einfach. 24. Juni 2010 35
  • 36. Categories Piet Mondrian, Composition with Gray and Light Brown 36
  • 37. Tests in Kategorien einteilen Kategorie ist Klasse oder Interface: public interface Slow {} Einzelner Test: @Category(Slow.class) @Test public void test() {} Alle Tests einer Klasse: @Category(Slow.class) public class B { @Test public void c() {} } 24. Juni 2010 37
  • 38. Tests in bestimmten Kategorien ausführen Herkömmliche Test-Suite: @RunWith(Suite.class) @SuiteClasses( { A.class, B.class }) public class AllTests {} Alle Tests in der Kategorie Slow: @RunWith(Categories.class) @IncludeCategory(Slow.class) public class AllSlowTests extends AllTests {} Alle anderen Tests: @RunWith(Categories.class) @ExcludeCategory(Slow.class) public class AllFastTests extends AllTests {} 24. Juni 2010 38
  • 39. Ausblick Quint Buchholz, Mann auf einer Leiter 39
  • 40. Was jetzt? Aktualisierung auf neue Version ist einfach Alte Tests funktionieren weiterhin Neue Tests profitieren von neuen Features Alte Tests können nach und nach vereinfacht werden Ausprobieren! 24. Juni 2010 40
  • 41. Ausprobieren! http://www.junit.org/ Grau is alle Theorie – entscheidend is auf’m Platz – Adi Preissler Vielen Dank! Mail marc@andrena.de Twitter marcphilipp Blog http://marcphilipp.tumblr.com/ 24. Juni 2010 41