Spock vs Supermutanten: Spezifikationstesten trifft Mutationstesten

Spock vs Supermutanten: Spezifikationstesten trifft Mutationstesten

04.02.2020, OOP München

https://www.code-days.de/programm/programm-details/411/spock-vs-supermutanten-spezifikationstesten-trifft-mutationstesten/

Das Spock Testframework verwendet das ausdrucksstarke Groovy um BDD als Testansatz zu realisieren. Neben einer klaren Teststruktur punktet es mit lesbaren Reports, die dank einer Template-Engine auch in AsciiDoc generiert werden können. Kann man das noch verbessern? Wir treten den Beweis an und kombinieren Spock mit Mutationstests. Denn eine Testabdeckung von über 80 % beweist noch nicht, dass die Testsuite in der Lage ist Fehler zuverlässig zu erkennen. Der Vortrag zeigt, wie sich Spock mit Mutationstesten zu einem cleveren Duo kombinieren lässt.

Zielpublikum: Software-Architekten, Software-Entwickler, Web-Entwickler, IT-Consultants

Cc5f3bf8b3cb91c985ed4fd046aa451d?s=128

Ralf D. Müller

February 04, 2020
Tweet

Transcript

  1. Ralf D. Müller @RalfDMueller Johannes Dienst @JohannesDienst Spock vs Supermutanten

    Spezifikationstesten trifft auf Mutationstesten
  2. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst Was ist

    Spock?
  3. Was ist Spock? 3 Leonard Brüning Ralf D. Müller @RalfDMueller

    und Johannes Dienst @JohannesDienst
  4. Was ist Spock? 4 private Fibonacci fib; @Before public void

    setup() { fib = new Fibonacci(); } @Test public void seedValue0() { assertEquals(0, fib.calc(0)); } @Test public void seedValue1() { assertEquals(1, fib.calc(1)); } // … Developer Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst
  5. Was ist Spock? 5 private Fibonacci fib; @Before public void

    setup() { fib = new Fibonacci(); } @Test public void seedValue0() { assertEquals(0, fib.calc(0)); } @Test public void seedValue1() { assertEquals(1, fib.calc(1)); } // … Developer Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst
  6. Was ist Spock? 6 private Fibonacci fib; @Before public void

    setup() { fib = new Fibonacci(); } @Test public void seedValue0() { assertEquals(0, fib.calc(0)); } @Test public void seedValue1() { assertEquals(1, fib.calc(1)); } // … Developer Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst
  7. Was ist Spock? 7 Fibonacci fib; @Before void setup() {

    fib = new Fibonacci(); } void seedValue0() { assertEquals(0, fib.calc(0)); } void seedValue1() { assertEquals(1, fib.calc(1)); } // … Developer Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst
  8. Was ist Spock? 8 Fibonacci fib; @Before void setup() {

    fib = new Fibonacci(); } void "test the fibonacci generator with input 0"() { assertEquals(0, fib.calc(0)); } void "test the fibonacci generator with input 1" { assertEquals(1, fib.calc(1)); } // … Developer Product Owner Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst
  9. Was ist Spock? 9 Fibonacci fib; @Before void setup() {

    fib = new Fibonacci(); } void "test the fibonacci generator with input 0"() { given: Fibonacci fib = new Fibonacci() when: def result = fib.calc(i) then: assertEquals(0, result); } void "test the fibonacci generator with input 1" { assertEquals(1, fib.calc(1)); } // … Developer Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst
  10. Was ist Spock? 10 void "test the fibonacci generator with

    input 0"() { given: Fibonacci fib = new Fibonacci() when: def result = fib.calc(i) then: assertEquals(0, result); } void "test the fibonacci generator with input 1" { assertEquals(1, fib.calc(1)); } // … Developer Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst
  11. Was ist Spock? 11 void "test the fibonacci generator with

    input 0"() { given: "an instance of the fibonacci generator" Fibonacci fib = new Fibonacci() when: "the fib sequence for 0 is calculated" def result = fib.calc(i) then: "the expected number is returned" assertEquals(0, result); } void "test the fibonacci generator with input 1" { assertEquals(1, fib.calc(1)); } // … Developer Product Owner Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst
  12. Was ist Spock? 12 void "test the fibonacci generator with

    input 0"() { given: "an instance of the fibonacci generator" Fibonacci fib = new Fibonacci() when: "the fib sequence for 0 is calculated" def result = fib.calc(i) then: "the expected number is returned" result == 0 } void "test the fibonacci generator with input 1" { assertEquals(1, fib.calc(1)); } // … Developer Product Owner Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst
  13. Was ist Spock? 13 void "test the fibonacci generator with

    input 0"() { given: "an instance of the fibonacci generator" Fibonacci fib = new Fibonacci() when: "the fib sequence for a given input #i is calculated" def result = fib.calc(i) then: "the expected number #expected is returned" result == expected where: i || expected 0 || 0 2 || 1 11 || 89 } Developer Product Owner Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst
  14. DB Systel. Digital bewegen. Gemeinsam. Ralf D. Müller @RalfDMueller und

    Johannes Dienst @JohannesDienst 14 Reports
  15. DB Systel. Digital bewegen. Gemeinsam. Ralf D. Müller @RalfDMueller und

    Johannes Dienst @JohannesDienst 15 Reports
  16. DB Systel. Digital bewegen. Gemeinsam. Ralf D. Müller @RalfDMueller und

    Johannes Dienst @JohannesDienst 16 Reports Product Owner Developer
  17. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 17 Zeilenabdeckung?

  18. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 18 100%

    Icons made by Sprang from www.flaticon.com
  19. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 19 Finde

    den Fehler? public List<Integer> sort(List<Integer> coll) { List<Integer> list = new ArrayList<>(coll); Collections.sort(list); log(list); return Collections.unmodifiableList(list); } public void log(List<Integer> list) { System.out.println( list.stream().map(Object::toString) .collect(Collectors.joining(", "))); } Icons made by Sprang from www.flaticon.com
  20. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 20 Finde

    den Fehler? def "test Sort"() { given: "an instance of Sort" def Sort = new Sort() when: "the given list #list is sorted" def result = Sort.sort(list) then: "the result is as #expected" result == expected where: "" list || expected [] || [] [5] || [5] [2,1,3,8] || [1,2,3,8] } Icons made by Sprang from www.flaticon.com
  21. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 21 Finde

    den Fehler? public List<Integer> sort(List<Integer> coll) { List<Integer> list = new ArrayList<>(coll); Collections.sort(list); log(list); return Collections.unmodifiableList(list); } public void log(List<Integer> list) { System.out.println( list.stream().map(Object::toString) .collect(Collectors.joining(", "))); } Icons made by Sprang from www.flaticon.com
  22. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 22 Und

    nun? Icons made by Sprang from www.flaticon.com
  23. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 23 Fehler

    gezielt provozieren Icons made by Sprang from www.flaticon.com
  24. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 24 Automatisierung

    Icons made by Sprang from www.flaticon.com
  25. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 25 Mutationstesten

    Icons made by Sprang from www.flaticon.com
  26. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 26 Mutationstesten

    - Funktionsweise Icons made by Sprang from www.flaticon.com
  27. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 27 DEMO

    HTML Report Icons made by Sprang from www.flaticon.com
  28. Increments Mutator i++ wird zu i-- Math Mutator + wird

    zu - * wird zu / Negate Conditionals Mutator == wird zu != <= wird zu > Conditionals Boundary Mutator < wird zu <= <= wird zu < Invert Negs Mutator -i wird zu i Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 28 Default Mutatoren
  29. Increments Mutator i++ wird zu i-- Math Mutator + wird

    zu - * wird zu / Negate Conditionals Mutator == wird zu != <= wird zu > Conditionals Boundary Mutator < wird zu <= <= wird zu < Invert Negs Mutator -i wird zu i Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 29 Default Mutatoren
  30. Increments Mutator i++ wird zu i-- Math Mutator + wird

    zu - * wird zu / Negate Conditionals Mutator == wird zu != <= wird zu > Conditionals Boundary Mutator < wird zu <= <= wird zu < Invert Negs Mutator -i wird zu i Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 30 Default Mutatoren
  31. Increments Mutator i++ wird zu i-- Math Mutator + wird

    zu - * wird zu / Negate Conditionals Mutator == wird zu != <= wird zu > Conditionals Boundary Mutator < wird zu <= <= wird zu < Invert Negs Mutator -i wird zu i Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 31 Default Mutatoren
  32. Increments Mutator i++ wird zu i-- Math Mutator + wird

    zu - * wird zu / Negate Conditionals Mutator == wird zu != <= wird zu > Conditionals Boundary Mutator < wird zu <= <= wird zu < Invert Negs Mutator -i wird zu i Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 32 Default Mutatoren
  33. public Object foo() { return new Object(); } Ralf D.

    Müller @RalfDMueller und Johannes Dienst @JohannesDienst 33 Code Smells finden mit dem Return Values Mutator public Object foo() { new Object(); return null; }
  34. public Object foo() { return new Object(); } Ralf D.

    Müller @RalfDMueller und Johannes Dienst @JohannesDienst 34 Code Smells finden mit dem Return Values Mutator public Object foo() { new Object(); return null; }
  35. DB Systel. Digital bewegen. Gemeinsam. Ralf D. Müller @RalfDMueller und

    Johannes Dienst @JohannesDienst 35 Dead Code finden mit dem Void Method Call Mutator public List<Integer> sort(List<Integer> coll) { List<Integer> list = new ArrayList<>(coll); Collections.sort(list); log(list); return Collections.unmodifiableList(list); } public void log(List<Integer> list) { System.out.println( list.stream().map(Object::toString) .collect(Collectors.joining(", "))); } Icons made by Sprang from www.flaticon.com
  36. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 36 Äquivalente

    Mutationen public int calc(int i) { if (i == 0) { return 0; } if (i <= 2) { return 1; } return calc(i-1) + calc(i-2); } def "test fibonacci generator"() { given: "fibonacci generator" Fibonacci fib = new Fibonacci() when: "calc sequence for input #i" def result = fib.calc(i) then: "expected number is returned" result == expected where: i || expected 0 || 0 2 || 1 11 || 89 } i < 2 Icons made by Sprang from www.flaticon.com
  37. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 37 Warum

    PIT? Schnell durch Parallelisierung Arbeitet auf Bytecode Lesbare Reports Tooling
  38. DB Systel. Digital bewegen. Gemeinsam. Ralf D. Müller @RalfDMueller und

    Johannes Dienst @JohannesDienst 38
  39. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 39 Mutationstesten

    – im größeren Team Icons made by Sprang from www.flaticon.com
  40. Ralf D. Müller @RalfDMueller und Johannes Dienst @JohannesDienst 40 Mutationstesten

    – im größeren Team Icons made by Sprang from www.flaticon.com
  41. 41

  42. 42

  43. 43

  44. Welche zwei Fragen sind noch offen? Johannes.Dienst@DeutscheBahn.com @JohannesDienst Ralf.D.Mueller@DeutscheBahn.com @RalfDMueller

  45. DB Systel. Digital bewegen. Gemeinsam. Ralf D. Müller @RalfDMueller und

    Johannes Dienst @JohannesDienst 45 https://jaxenter.de/mutant-testing-pit-java-84437 https://m.heise.de/developer/artikel/Mutationstests-mit-PIT-in- Java-3888683.html?seite=all