SlideShare una empresa de Scribd logo
1 de 37
JDays 2015
AlexanderTarnowski
Dealing with combinatorial explosionsand
boring tests
 Developer (2000→) Java, Perl, C, C++, Groovy, C#, PHP,
Visual Basic, Assembler
 Trainer – TDD, Unit testing, Clean Code, WebDriver,
Specification by Example
 Developer mentor
 Writer
 Scrum Master
 Coach in training
WhoamI?
https://www.crisp.se/konsulter/alexander-tarnowski
alexander_tar
alexander.tarnowski@crisp.se
”We want our
customers to be able
to compute their car
insurance premiums
online.
Online quotes are in
our favor, since we
outprice our
competitors!”
Who is Tim?
Image: stockimages/freedigitalphotos.net
Alexander Tarnowski
Age Premium for males Premium for females
18-23 1.75 1.575
24-59 1.0 0.9
60+ 1.35 1.215
Business rules
Alexander Tarnowski
@Test
public void maleDriversAged18() {
assertEquals(1.75, new PremiumRuleEngine()
.getPremiumFactor(18, Gender.MALE), 0.0);
}
The first test
Age Premium for males Premium for females
18-23 1.75 1.575
24-59 1.0 0.9
60+ 1.35 1.215
Alexander Tarnowski
@Test
public void maleDriversAged23() {
assertEquals(1.75, new PremiumRuleEngine()
.getPremiumFactor(23, Gender.MALE), 0.0);
}
The second test
Age Premium for males Premium for females
18-23 1.75 1.575
24-59 1.0 0.9
60+ 1.35 1.215
Alexander Tarnowski
And this could go on…
Image: imagerymajestic/freedigitalphotos.net
Alexander Tarnowski
 Silly names
 Repetitive test structure
 Boredom
Smells and insights
Image: Mister GC/freedigitalphotos.net
Alexander Tarnowski
 How many equivalence classes?
 How many boundary values?
 Would we test drive all of them?
How many tests are needed?
0
0.5
1
1.5
2
18-23 24-59 60+
Male
Female
Alexander Tarnowski
@RunWith(Parameterized.class)
public class PremiumAgeIntervalsTest {
private double expectedPremiumFactor;
private int age;
private Gender gender;
public PremiumAgeIntervalsTest(double expectedPremiumFactor, int age, Gender gender) {
this.expectedPremiumFactor = expectedPremiumFactor;
this.age = age;
this.gender = gender;
}
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{1.75, 18, Gender.MALE}, {1.75, 23, Gender.MALE}, {1.0, 24, Gender.MALE},
{1.0, 59, Gender.MALE}, {1.35, 60, Gender.MALE}, {1.575, 18, Gender.FEMALE},
{1.575, 23, Gender.FEMALE}, {0.9, 24, Gender.FEMALE}, {0.9, 59, Gender.FEMALE},
{1.215, 60, Gender.FEMALE}}
);
}
@Test
public void verifyPremiumFactor() {
assertEquals(expectedPremiumFactor, new PremiumRuleEngine()
.getPremiumFactor(age, gender), 0.0);
}
}
Theparameterized version
Alexander Tarnowski
@RunWith(Parameterized.class)
public class PremiumAgeIntervalsTest {
@Parameter(value = 0)
public double expectedPremiumFactor;
@Parameter(value = 1)
public int age;
@Parameter(value = 2)
public Gender gender;
@Parameters(name = "Case {index}: Expected {0} for {1} year old {2}s")
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{1.75, 18, Gender.MALE}, {1.75, 23, Gender.MALE}, {1.0, 24, Gender.MALE},
{1.0, 59, Gender.MALE}, {1.35, 60, Gender.MALE}, {1.575, 18, Gender.FEMALE},
{1.575, 23, Gender.FEMALE}, {0.9, 24, Gender.FEMALE}, {0.9, 59, Gender.FEMALE},
{1.215, 60, Gender.FEMALE}}
);
}
@Test
public void verifyPremiumFactor() {
assertEquals(expectedPremiumFactor, new PremiumRuleEngine()
.getPremiumFactor(age, gender), 0.0);
}
}
Alternative syntax
Alexander Tarnowski
 Focus on data
 Allow comparing a set of predefined inputs with
some predefined output
 Make checking simple
 Turn tests with silly names into data-driven tests
Parameterized tests
Alexander Tarnowski
 Interface
 Happy path
 Learning
 Error handling
TDD vsTesting
TDD Testing(checking)
 Equivalence partitions
 Boundary values
 Decision tables
 State machines
Alexander Tarnowski
@Test
public void aHamburgerIsnHealthyFood() {
assertThat(Menu.HAMBURGER.getCalories(),
greaterThan(200));
}
Speaking offood…
Alexander Tarnowski
Hamburgers contain the
least amount of calories
among common fast foods
Theory
Alexander Tarnowski
public class CalorieComparisonTest {
public static List<FastFood> foods() {
return Arrays.asList(Menu.FISH_BURGER,
Menu.GIGANTIC_BURGER_WITH_BACON, Menu.CHICKEN_SANDWICH,
Menu.HOTDOG);
}
@Test
public void hamburgersContainTheLeastAmountOfCaloriesAmongFastFoods() {
for (FastFood food : foods())
assertThat(Menu.HAMBURGER.getCalories(),
is(lessThan(food.getCalories())));
}
}
}
Proving the theory
Alexander Tarnowski
@RunWith(Theories.class)
public class CalorieComparisonTest {
@DataPoints
public static List<FastFood> foods() {
return Arrays.asList(Menu.FISH_BURGER,
Menu.GIGANTIC_BURGER_WITH_BACON, Menu.CHICKEN_SANDWICH,
Menu.HOTDOG);
}
@Theory
public void hamburgersContainTheLeastAmountOfCaloriesAmongFastFoods(FastFood food)
{
assertThat(Menu.HAMBURGER.getCalories(),
is(lessThan(food.getCalories())));
}
}
Atheorytest
Alexander Tarnowski
 No fast food meal contains
less than 500 calories!
Amore interesting theory
Image: marin/freedigitalphotos.net
Alexander Tarnowski
@RunWith(Theories.class)
public class FastFoodMealTheoryTest {
@DataPoints
public static List<Main> mainCourses() {
return Arrays.asList(Menu.HAMBURGER, Menu.FISH_BURGER,
Menu.GIGANTIC_BURGER_WITH_BACON, Menu.CHICKEN_SANDWICH,
Menu.HOTDOG);
}
@DataPoints
public static List<SideOrder> sideOrders() {
return Arrays.asList(Menu.SMALL_FRENCH_FRIES, Menu.LARGE_FRENCH_FRIES,
Menu.APPLE_PIE, Menu.SMALL_CHOCOLATE_MILKSHAKE);
}
@DataPoints
public static List<Beverage> bevereges() {
return Arrays.asList(Menu.MEDIUM_COKE, Menu.LARGE_DIET_COKE,
Menu.MEDIUM_LATTE, Menu.LARGE_LATTE);
}
@Theory
public void noFastFoodMealContainsLessThan500calories(Main main,
SideOrder sideOrder,
Beverage beverage) {
assumeThat(beverage.isDiet(), is(false));
assertThat(main.getCalories() + sideOrder.getCalories() + beverage.getCalories(),
is(greaterThan(500)));
}
}
Alexander Tarnowski
 Feed the test with all main courses and all side
orders and all beverages
 Cartesian product: mains X side orders X
beverages
 assumeThat prunes some combinations
Behind the scenes
(Hamburger, Small french fries, Medium coke)
(Hamburger, Small french fries, Large diet coke)
(Hamburger, Small french fries, Medium latte)
(Hamburger, Small french fries, Large latte)
(Hamburger, Large french fries, Medium coke)
(Hamburger, Large french fries, Large diet coke)
(Hamburger, Large french fries, Medium latte)
(Hamburger, Large french fries, Large latte)
…
Alexander Tarnowski
 Are built around ”for all” type of reasoning
 Can’t pair specific data points with specific results
 Let you work with the Cartesian product of
multiple variables
Theories
Alexander Tarnowski
Let’s do the Caesarcipher…
A B C D E F G H I J K L M O P Q R S T U V X Y Z
S T U V X Y Z A B C D E F G H I J K L M O P Q R
CAESAR=USXKSJ
Alexander Tarnowski
Does it work?
… by borrowing an onlineimplementation
Alexander Tarnowski
 For a bunch of different arbitrary strings…
 ... and a bunch of different offsets...
 ... try the following:
CaesarCipher.decode(CaesarCipher.encode(string, offset), offset)
Dream scenario
Alexander Tarnowski
@RunWith(Theories.class)
public class CaesarCipherTest {
@Theory
public void caesarCipherRoundTrip(@RandomString(maxLength = 128) String plainText,
@TestedOn(ints = {0, 1, 2, 10, 26, 27, 1000}) int offset) {
assertEquals(plainText, CaesarCipher.decode(CaesarCipher.encode(plainText, offset),
offset));
}
}
We can do that!
Alexander Tarnowski
RandomString.java:
@Retention(RetentionPolicy.RUNTIME)
@ParametersSuppliedBy(RandomStringSupplier.class)
public @interface RandomString {
int maxLength();
}
RandomStringSupplier.java:
public class RandomStringSupplier extends ParameterSupplier {
@Override
public List<PotentialAssignment> getValueSources(ParameterSignature signature)
throws Throwable {
RandomString annotation = signature.getAnnotation(RandomString.class);
int length = (int) (Math.random() * annotation.maxLength());
final String s = RandomStringUtils.randomAlphanumeric(length);
return Arrays.asList(PotentialAssignment.forValue("random string", s));
}
}
@RandomString
Alexander Tarnowski
RandomStringsSupplier.java:
public class RandomsStringSupplier extends ParameterSupplier {
@Override
public List<PotentialAssignment> getValueSources(ParameterSignature signature) throws
Throwable {
List<PotentialAssignment> values = new ArrayList<>();
RandomStrings annotation = signature.getAnnotation(RandomStrings.class);
Generator<String> stringGenerator
= strings(integers(1, 128, Distribution.INVERTED_NORMAL), characters());
for (int i = 0; i < annotation.count(); i++) {
values.add(PotentialAssignment.forValue("random string", stringGenerator.next()));
}
return values;
}
}
QuickCheck style
Alexander Tarnowski
Examples of generators
 booleans()
 dates(Long low, Long high, TimeUnit precision)
 fixedValues(T... values)
 strings(Generator<Integer> length, Generator<Character> characters)
 arrays(Generator<? extends T> content, Class<T> type)
 excludeValues(Generator<T> generator, T... excluded)
 sortedLists(Generator<T> content, int low, int high)
net.java.quickcheck
public interface Generator<T> {
/**
* Generates the next instance.
*
* @return a newly created instance
*/
public T next();
}
Alexander Tarnowski
 Anything goes!
 May involve huge domains
 Often involves inverse functions
Generative testing
Alexander Tarnowski
 Now we can execute thousands of tests!
 But what if we want the opposite?
Congratulations!
Alexander TarnowskiImage: zole4/freedigitalphotos.net
Back to car insurance premiums
Gender
Male
Female
Age interval
18-24
25-59
60+
Yearly mileage
0
1-1000
1001-3000
3001-6000
6001+
Safety features
None
Airbag
ABS
HIP
Multiple
Brand
Nissan
Volvo
Ferrari
Toyota
Ford
Volkswagen
Driving record
Model Driver
Average Joe
Unlucky Uma
Bad Judgement Jed
Dangerous Dan
2 x 3 x 5 x 5 x 6 x 5
= 4500
Alexander Tarnowski
 One parameter causes the error
 Only 6 tests are needed!
Single mode faults
Brand Drivingrecord Yearlymileage Safetyfeatures Ageinterval Gender
Nissan ModelDriver 0 None 18-24 Male
Volvo AverageJoe 1-1000 Airbag 25-59 Female
Ferrari UnluckyUma 1001-3000 ABS 60+ -
Toyota BadJudgementJed 3001-6000 HIP - -
Ford DangerousDan 6001+ Multiple - -
Volkswagen - - - - -
Alexander Tarnowski
 A combination of two parameters causes the error
 Run through a tool that computes all pairs (or look
up in a table of orthogonal arrays)
 Only ~40 tests are needed!
Double mode faults
Alexander Tarnowski
Finding all pairs by hand
Row Variable 1 Variable 2 Variable 3
1 A X Q
2 A X R
3 A Y Q
4 A Y R
5 B X Q
6 B X R
7 B Y Q
8 B Y R
Alexander Tarnowski
 Theoretical foundation: orthogonal arrays
 Reduce the number of tests from thousands to
just a few
 Great to put into parameterized tests
Finding Single and Doublemode faults
Alexander Tarnowski
 Unit tests are examples
 Parameterized tests make writing many similar
tests easy
 Theory tests introduce general statements about
program elements
 Generative tests – Anything goes!
 Single mode faults & double mode faults –
Reduce the number of tests and feed
parameterized tests
Summary
Alexander Tarnowski
 https://leanpub.com/developer_testing
 http://web.archive.org/web/20110808084654/http://shareandenjoy.saff.net/tdd-
specifications.pdf
 https://github.com/junit-team/junit/wiki/Theories
 https://github.com/pholser/junit-quickcheck
 http://www.satisfice.com/tools.shtml
Some resources
Alexander Tarnowski

Más contenido relacionado

La actualidad más candente

Java Puzzle
Java PuzzleJava Puzzle
Java Puzzle
SFilipp
 
Codestrong 2012 breakout session hacking titanium
Codestrong 2012 breakout session   hacking titaniumCodestrong 2012 breakout session   hacking titanium
Codestrong 2012 breakout session hacking titanium
Axway Appcelerator
 

La actualidad más candente (20)

Java Puzzle
Java PuzzleJava Puzzle
Java Puzzle
 
Final JAVA Practical of BCA SEM-5.
Final JAVA Practical of BCA SEM-5.Final JAVA Practical of BCA SEM-5.
Final JAVA Practical of BCA SEM-5.
 
Java practical
Java practicalJava practical
Java practical
 
Concurrency Concepts in Java
Concurrency Concepts in JavaConcurrency Concepts in Java
Concurrency Concepts in Java
 
Mutation @ Spotify
Mutation @ Spotify Mutation @ Spotify
Mutation @ Spotify
 
Java puzzles
Java puzzlesJava puzzles
Java puzzles
 
RxJava и Android. Плюсы, минусы, подводные камни
RxJava и Android. Плюсы, минусы, подводные камниRxJava и Android. Плюсы, минусы, подводные камни
RxJava и Android. Плюсы, минусы, подводные камни
 
Taking the boilerplate out of your tests with Sourcery
Taking the boilerplate out of your tests with SourceryTaking the boilerplate out of your tests with Sourcery
Taking the boilerplate out of your tests with Sourcery
 
Machine Learning Model Bakeoff
Machine Learning Model BakeoffMachine Learning Model Bakeoff
Machine Learning Model Bakeoff
 
Core java pract_sem iii
Core java pract_sem iiiCore java pract_sem iii
Core java pract_sem iii
 
Java_practical_handbook
Java_practical_handbookJava_practical_handbook
Java_practical_handbook
 
Ember
EmberEmber
Ember
 
Java practical(baca sem v)
Java practical(baca sem v)Java practical(baca sem v)
Java practical(baca sem v)
 
DCN Practical
DCN PracticalDCN Practical
DCN Practical
 
Spotify 2016 - Beyond Lambdas - the Aftermath
Spotify 2016 - Beyond Lambdas - the AftermathSpotify 2016 - Beyond Lambdas - the Aftermath
Spotify 2016 - Beyond Lambdas - the Aftermath
 
Java Puzzlers
Java PuzzlersJava Puzzlers
Java Puzzlers
 
Codestrong 2012 breakout session hacking titanium
Codestrong 2012 breakout session   hacking titaniumCodestrong 2012 breakout session   hacking titanium
Codestrong 2012 breakout session hacking titanium
 
Compact and safely: static DSL on Kotlin
Compact and safely: static DSL on KotlinCompact and safely: static DSL on Kotlin
Compact and safely: static DSL on Kotlin
 
JDays 2016 - Beyond Lambdas - the Aftermath
JDays 2016 - Beyond Lambdas - the AftermathJDays 2016 - Beyond Lambdas - the Aftermath
JDays 2016 - Beyond Lambdas - the Aftermath
 
Angular2 rxjs
Angular2 rxjsAngular2 rxjs
Angular2 rxjs
 

Similar a Dealing with combinatorial explosions and boring tests

33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests
Tomek Kaczanowski
 
About java
About javaAbout java
About java
Jay Xu
 
An introduction to property-based testing
An introduction to property-based testingAn introduction to property-based testing
An introduction to property-based testing
Vincent Pradeilles
 

Similar a Dealing with combinatorial explosions and boring tests (20)

Stored Procedures and MUMPS for DivConq
 Stored Procedures and  MUMPS for DivConq  Stored Procedures and  MUMPS for DivConq
Stored Procedures and MUMPS for DivConq
 
Transaction is a monad
Transaction is a  monadTransaction is a  monad
Transaction is a monad
 
2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests
 
An Introduction to Property Based Testing
An Introduction to Property Based TestingAn Introduction to Property Based Testing
An Introduction to Property Based Testing
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests
 
JUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit TestsJUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit Tests
 
Developer Testing Tools Roundup
Developer Testing Tools RoundupDeveloper Testing Tools Roundup
Developer Testing Tools Roundup
 
Ann
AnnAnn
Ann
 
Effective Java with Groovy
Effective Java with GroovyEffective Java with Groovy
Effective Java with Groovy
 
Property Based Testing
Property Based TestingProperty Based Testing
Property Based Testing
 
Poly-paradigm Java
Poly-paradigm JavaPoly-paradigm Java
Poly-paradigm Java
 
MongoDB World 2019: Life In Stitch-es
MongoDB World 2019: Life In Stitch-esMongoDB World 2019: Life In Stitch-es
MongoDB World 2019: Life In Stitch-es
 
Not your father's tests
Not your father's testsNot your father's tests
Not your father's tests
 
JUnit Pioneer
JUnit PioneerJUnit Pioneer
JUnit Pioneer
 
About java
About javaAbout java
About java
 
How to ship customer value faster with step functions
How to ship customer value faster with step functionsHow to ship customer value faster with step functions
How to ship customer value faster with step functions
 
An introduction to property-based testing
An introduction to property-based testingAn introduction to property-based testing
An introduction to property-based testing
 
Pattern Matching in Java 14
Pattern Matching in Java 14Pattern Matching in Java 14
Pattern Matching in Java 14
 
Ruslan Shevchenko - Property based testing
Ruslan Shevchenko - Property based testingRuslan Shevchenko - Property based testing
Ruslan Shevchenko - Property based testing
 
How to not write a boring test in Golang
How to not write a boring test in GolangHow to not write a boring test in Golang
How to not write a boring test in Golang
 

Último

%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
masabamasaba
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
VictoriaMetrics
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 

Último (20)

VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 

Dealing with combinatorial explosions and boring tests

  • 1. JDays 2015 AlexanderTarnowski Dealing with combinatorial explosionsand boring tests
  • 2.  Developer (2000→) Java, Perl, C, C++, Groovy, C#, PHP, Visual Basic, Assembler  Trainer – TDD, Unit testing, Clean Code, WebDriver, Specification by Example  Developer mentor  Writer  Scrum Master  Coach in training WhoamI? https://www.crisp.se/konsulter/alexander-tarnowski alexander_tar alexander.tarnowski@crisp.se
  • 3. ”We want our customers to be able to compute their car insurance premiums online. Online quotes are in our favor, since we outprice our competitors!” Who is Tim? Image: stockimages/freedigitalphotos.net Alexander Tarnowski
  • 4. Age Premium for males Premium for females 18-23 1.75 1.575 24-59 1.0 0.9 60+ 1.35 1.215 Business rules Alexander Tarnowski
  • 5. @Test public void maleDriversAged18() { assertEquals(1.75, new PremiumRuleEngine() .getPremiumFactor(18, Gender.MALE), 0.0); } The first test Age Premium for males Premium for females 18-23 1.75 1.575 24-59 1.0 0.9 60+ 1.35 1.215 Alexander Tarnowski
  • 6. @Test public void maleDriversAged23() { assertEquals(1.75, new PremiumRuleEngine() .getPremiumFactor(23, Gender.MALE), 0.0); } The second test Age Premium for males Premium for females 18-23 1.75 1.575 24-59 1.0 0.9 60+ 1.35 1.215 Alexander Tarnowski
  • 7. And this could go on… Image: imagerymajestic/freedigitalphotos.net Alexander Tarnowski
  • 8.  Silly names  Repetitive test structure  Boredom Smells and insights Image: Mister GC/freedigitalphotos.net Alexander Tarnowski
  • 9.  How many equivalence classes?  How many boundary values?  Would we test drive all of them? How many tests are needed? 0 0.5 1 1.5 2 18-23 24-59 60+ Male Female Alexander Tarnowski
  • 10. @RunWith(Parameterized.class) public class PremiumAgeIntervalsTest { private double expectedPremiumFactor; private int age; private Gender gender; public PremiumAgeIntervalsTest(double expectedPremiumFactor, int age, Gender gender) { this.expectedPremiumFactor = expectedPremiumFactor; this.age = age; this.gender = gender; } @Parameters public static Collection<Object[]> data() { return Arrays.asList(new Object[][]{ {1.75, 18, Gender.MALE}, {1.75, 23, Gender.MALE}, {1.0, 24, Gender.MALE}, {1.0, 59, Gender.MALE}, {1.35, 60, Gender.MALE}, {1.575, 18, Gender.FEMALE}, {1.575, 23, Gender.FEMALE}, {0.9, 24, Gender.FEMALE}, {0.9, 59, Gender.FEMALE}, {1.215, 60, Gender.FEMALE}} ); } @Test public void verifyPremiumFactor() { assertEquals(expectedPremiumFactor, new PremiumRuleEngine() .getPremiumFactor(age, gender), 0.0); } } Theparameterized version Alexander Tarnowski
  • 11. @RunWith(Parameterized.class) public class PremiumAgeIntervalsTest { @Parameter(value = 0) public double expectedPremiumFactor; @Parameter(value = 1) public int age; @Parameter(value = 2) public Gender gender; @Parameters(name = "Case {index}: Expected {0} for {1} year old {2}s") public static Collection<Object[]> data() { return Arrays.asList(new Object[][]{ {1.75, 18, Gender.MALE}, {1.75, 23, Gender.MALE}, {1.0, 24, Gender.MALE}, {1.0, 59, Gender.MALE}, {1.35, 60, Gender.MALE}, {1.575, 18, Gender.FEMALE}, {1.575, 23, Gender.FEMALE}, {0.9, 24, Gender.FEMALE}, {0.9, 59, Gender.FEMALE}, {1.215, 60, Gender.FEMALE}} ); } @Test public void verifyPremiumFactor() { assertEquals(expectedPremiumFactor, new PremiumRuleEngine() .getPremiumFactor(age, gender), 0.0); } } Alternative syntax Alexander Tarnowski
  • 12.  Focus on data  Allow comparing a set of predefined inputs with some predefined output  Make checking simple  Turn tests with silly names into data-driven tests Parameterized tests Alexander Tarnowski
  • 13.  Interface  Happy path  Learning  Error handling TDD vsTesting TDD Testing(checking)  Equivalence partitions  Boundary values  Decision tables  State machines Alexander Tarnowski
  • 14. @Test public void aHamburgerIsnHealthyFood() { assertThat(Menu.HAMBURGER.getCalories(), greaterThan(200)); } Speaking offood… Alexander Tarnowski
  • 15. Hamburgers contain the least amount of calories among common fast foods Theory Alexander Tarnowski
  • 16. public class CalorieComparisonTest { public static List<FastFood> foods() { return Arrays.asList(Menu.FISH_BURGER, Menu.GIGANTIC_BURGER_WITH_BACON, Menu.CHICKEN_SANDWICH, Menu.HOTDOG); } @Test public void hamburgersContainTheLeastAmountOfCaloriesAmongFastFoods() { for (FastFood food : foods()) assertThat(Menu.HAMBURGER.getCalories(), is(lessThan(food.getCalories()))); } } } Proving the theory Alexander Tarnowski
  • 17. @RunWith(Theories.class) public class CalorieComparisonTest { @DataPoints public static List<FastFood> foods() { return Arrays.asList(Menu.FISH_BURGER, Menu.GIGANTIC_BURGER_WITH_BACON, Menu.CHICKEN_SANDWICH, Menu.HOTDOG); } @Theory public void hamburgersContainTheLeastAmountOfCaloriesAmongFastFoods(FastFood food) { assertThat(Menu.HAMBURGER.getCalories(), is(lessThan(food.getCalories()))); } } Atheorytest Alexander Tarnowski
  • 18.  No fast food meal contains less than 500 calories! Amore interesting theory Image: marin/freedigitalphotos.net Alexander Tarnowski
  • 19. @RunWith(Theories.class) public class FastFoodMealTheoryTest { @DataPoints public static List<Main> mainCourses() { return Arrays.asList(Menu.HAMBURGER, Menu.FISH_BURGER, Menu.GIGANTIC_BURGER_WITH_BACON, Menu.CHICKEN_SANDWICH, Menu.HOTDOG); } @DataPoints public static List<SideOrder> sideOrders() { return Arrays.asList(Menu.SMALL_FRENCH_FRIES, Menu.LARGE_FRENCH_FRIES, Menu.APPLE_PIE, Menu.SMALL_CHOCOLATE_MILKSHAKE); } @DataPoints public static List<Beverage> bevereges() { return Arrays.asList(Menu.MEDIUM_COKE, Menu.LARGE_DIET_COKE, Menu.MEDIUM_LATTE, Menu.LARGE_LATTE); } @Theory public void noFastFoodMealContainsLessThan500calories(Main main, SideOrder sideOrder, Beverage beverage) { assumeThat(beverage.isDiet(), is(false)); assertThat(main.getCalories() + sideOrder.getCalories() + beverage.getCalories(), is(greaterThan(500))); } } Alexander Tarnowski
  • 20.  Feed the test with all main courses and all side orders and all beverages  Cartesian product: mains X side orders X beverages  assumeThat prunes some combinations Behind the scenes (Hamburger, Small french fries, Medium coke) (Hamburger, Small french fries, Large diet coke) (Hamburger, Small french fries, Medium latte) (Hamburger, Small french fries, Large latte) (Hamburger, Large french fries, Medium coke) (Hamburger, Large french fries, Large diet coke) (Hamburger, Large french fries, Medium latte) (Hamburger, Large french fries, Large latte) … Alexander Tarnowski
  • 21.  Are built around ”for all” type of reasoning  Can’t pair specific data points with specific results  Let you work with the Cartesian product of multiple variables Theories Alexander Tarnowski
  • 22. Let’s do the Caesarcipher… A B C D E F G H I J K L M O P Q R S T U V X Y Z S T U V X Y Z A B C D E F G H I J K L M O P Q R CAESAR=USXKSJ Alexander Tarnowski
  • 23. Does it work? … by borrowing an onlineimplementation Alexander Tarnowski
  • 24.  For a bunch of different arbitrary strings…  ... and a bunch of different offsets...  ... try the following: CaesarCipher.decode(CaesarCipher.encode(string, offset), offset) Dream scenario Alexander Tarnowski
  • 25. @RunWith(Theories.class) public class CaesarCipherTest { @Theory public void caesarCipherRoundTrip(@RandomString(maxLength = 128) String plainText, @TestedOn(ints = {0, 1, 2, 10, 26, 27, 1000}) int offset) { assertEquals(plainText, CaesarCipher.decode(CaesarCipher.encode(plainText, offset), offset)); } } We can do that! Alexander Tarnowski
  • 26. RandomString.java: @Retention(RetentionPolicy.RUNTIME) @ParametersSuppliedBy(RandomStringSupplier.class) public @interface RandomString { int maxLength(); } RandomStringSupplier.java: public class RandomStringSupplier extends ParameterSupplier { @Override public List<PotentialAssignment> getValueSources(ParameterSignature signature) throws Throwable { RandomString annotation = signature.getAnnotation(RandomString.class); int length = (int) (Math.random() * annotation.maxLength()); final String s = RandomStringUtils.randomAlphanumeric(length); return Arrays.asList(PotentialAssignment.forValue("random string", s)); } } @RandomString Alexander Tarnowski
  • 27. RandomStringsSupplier.java: public class RandomsStringSupplier extends ParameterSupplier { @Override public List<PotentialAssignment> getValueSources(ParameterSignature signature) throws Throwable { List<PotentialAssignment> values = new ArrayList<>(); RandomStrings annotation = signature.getAnnotation(RandomStrings.class); Generator<String> stringGenerator = strings(integers(1, 128, Distribution.INVERTED_NORMAL), characters()); for (int i = 0; i < annotation.count(); i++) { values.add(PotentialAssignment.forValue("random string", stringGenerator.next())); } return values; } } QuickCheck style Alexander Tarnowski
  • 28. Examples of generators  booleans()  dates(Long low, Long high, TimeUnit precision)  fixedValues(T... values)  strings(Generator<Integer> length, Generator<Character> characters)  arrays(Generator<? extends T> content, Class<T> type)  excludeValues(Generator<T> generator, T... excluded)  sortedLists(Generator<T> content, int low, int high) net.java.quickcheck public interface Generator<T> { /** * Generates the next instance. * * @return a newly created instance */ public T next(); } Alexander Tarnowski
  • 29.  Anything goes!  May involve huge domains  Often involves inverse functions Generative testing Alexander Tarnowski
  • 30.  Now we can execute thousands of tests!  But what if we want the opposite? Congratulations! Alexander TarnowskiImage: zole4/freedigitalphotos.net
  • 31. Back to car insurance premiums Gender Male Female Age interval 18-24 25-59 60+ Yearly mileage 0 1-1000 1001-3000 3001-6000 6001+ Safety features None Airbag ABS HIP Multiple Brand Nissan Volvo Ferrari Toyota Ford Volkswagen Driving record Model Driver Average Joe Unlucky Uma Bad Judgement Jed Dangerous Dan 2 x 3 x 5 x 5 x 6 x 5 = 4500 Alexander Tarnowski
  • 32.  One parameter causes the error  Only 6 tests are needed! Single mode faults Brand Drivingrecord Yearlymileage Safetyfeatures Ageinterval Gender Nissan ModelDriver 0 None 18-24 Male Volvo AverageJoe 1-1000 Airbag 25-59 Female Ferrari UnluckyUma 1001-3000 ABS 60+ - Toyota BadJudgementJed 3001-6000 HIP - - Ford DangerousDan 6001+ Multiple - - Volkswagen - - - - - Alexander Tarnowski
  • 33.  A combination of two parameters causes the error  Run through a tool that computes all pairs (or look up in a table of orthogonal arrays)  Only ~40 tests are needed! Double mode faults Alexander Tarnowski
  • 34. Finding all pairs by hand Row Variable 1 Variable 2 Variable 3 1 A X Q 2 A X R 3 A Y Q 4 A Y R 5 B X Q 6 B X R 7 B Y Q 8 B Y R Alexander Tarnowski
  • 35.  Theoretical foundation: orthogonal arrays  Reduce the number of tests from thousands to just a few  Great to put into parameterized tests Finding Single and Doublemode faults Alexander Tarnowski
  • 36.  Unit tests are examples  Parameterized tests make writing many similar tests easy  Theory tests introduce general statements about program elements  Generative tests – Anything goes!  Single mode faults & double mode faults – Reduce the number of tests and feed parameterized tests Summary Alexander Tarnowski
  • 37.  https://leanpub.com/developer_testing  http://web.archive.org/web/20110808084654/http://shareandenjoy.saff.net/tdd- specifications.pdf  https://github.com/junit-team/junit/wiki/Theories  https://github.com/pholser/junit-quickcheck  http://www.satisfice.com/tools.shtml Some resources Alexander Tarnowski

Notas del editor

  1. Mister GC
  2. Has a for loop in it Violates the one assertion per test rule