Magda Stożek
Property-based testing
Let your testing library work for you
BigDecimal calculateDiscount(Customer customer, LocalDate now);
Example: Calculating discount
Years:
0-1
1-2
2 +
0%
30%
10%
20%
birthday
class Customer {
private final String name;
private final LocalDate joinedAt;
private final LocalDate dateOfBirth;
// (...)
}
Example-based tests
@Test
void shouldCalculateNoDiscount() {...}
@Test
void shouldCalculate10percentDiscount() {...}
@Test
void shouldCalculate20percentDiscount() {...}
@Test
void shouldCalculateBirthdayDiscount() {...}
@Test
void shouldCalculate20percentDiscountFor3Years() {...}
Happy path
Edge cases
What about properties?
BigDecimal calculateDiscount(Customer customer, LocalDate now);
Example: Calculating discount
Years:
0-1
1-2
2 +
0%
30%
10%
20%
birthday
class Customer {
private final String name;
private final LocalDate joinedAt;
private final LocalDate dateOfBirth;
// (...)
}
Property-based tests
@Property
void shouldNotBeLowerThan0() {...}
@Property
void shouldNotBeOver30percent() {...}
@Property
void shouldBeProportionalToMembershipYears() {...}
Properties:
@Property
void shouldNotBeGreaterThanBirthdayDiscount() {...}
@Property
boolean shouldNotBeOver30percent(
@ForAll Customer customer,
@ForAll("futureDate") LocalDate now)
{
BigDecimal discount = calculator.calculateDiscount(customer, now);
Assertions.assertThat(discount).compareTo(new BigDecimal("0.3")) <= 0;
}
Property: discount is never larger than 30%
Discovered error
|-------------------jqwik-------------------
tries = 374 | # of calls to property
checks = 374 | # of not rejected calls
generation-mode = RANDOMIZED | parameters are randomly generated
after-failure = PREVIOUS_SEED | use the previous seed
seed = -272292185905571017 | random seed to reproduce generated values
sample =
[Customer{name='AAA', joinedAt=2010-01-01, dateOfBirth=1980-02-29}, 2019-10-06]
original-sample =
[Customer{name='DtQDpPfEx', joinedAt=2010-04-21, dateOfBirth=1980-02-29}, 2185-03-17]
Challenges
Difficult questions earlier
Challenge #1
Nondeterminism
Challenge #2
Coming up with properties
Challenge #3
Strategies
1. Examples first, properties later
2. Properties for key components
Summary
- Higher cost, higher value
- Edge cases and misconceptions
- Coming up with properties
- Balance
More
@Property
boolean endOfPresentation(@ForAll Attendee attendee) {
Assert.that(attendee.wantsToTryIt);
}
Thanks!
Property-based testing [Java, 15 min]
By Magda Stożek
Property-based testing [Java, 15 min]
- 531