There are a couple (maybe more) libraries for property based testing, I found that jqwik worked well for me.
I’m not going to go too deep into what property based testing is, except to state that for my purposes, property based testing allows me to generate random values to pass into my tests. I can generate multiple “tries” or items of data and even restrict ranges of values.
Specifically I’m using property based testing to generate values for some unit conversion code, the values get converted to a different unit and back – if the resultant value is the same as the input value we can assume that the conversion back and forth works correctly.
Anyway there are plenty of resources to read on the subject, so let’s get stuck into some code.
First off we need the following dependency to our pom.xml (obviously change the version to suit)
<dependency> <groupId>net.jqwik</groupId> <artifactId>jqwik</artifactId> <version>1.6.2</version> <scope>test</scope> </dependency>
Let’s look a an example unit test
@Property(tries = 100) public void testFromDegreesToGradiansAndBack(@ForAll @DoubleRange(min = -1E12, max = 1E12) double value) { final double convertTo = Angle.Degrees.toGradians(value); final double convertBack = Angle.Gradians.toDegrees(convertTo); assertEquals(value, convertBack, 0.01); }
The @Property annotation tells the jqik runner to supply data for the method, creating 100 items of data (or tries) and @ForAll is used to assign data to the double value. Finally for this test I wanted to constrain the range of double values to [-1E12, 1E12].
The output (upon success) looks similar to this
timestamp = 2022-01-05T20:00:08.038391600, AngleTests:testFromDegreesToGradiansAndBack = |--------------------jqwik-------------------- tries = 100 | # of calls to property checks = 100 | # of not rejected calls generation = RANDOMIZED | parameters are randomly generated after-failure = PREVIOUS_SEED | use the previous seed when-fixed-seed = ALLOW | fixing the random seed is allowed edge-cases#mode = MIXIN | edge cases are mixed in edge-cases#total = 7 | # of all combined edge cases edge-cases#tried = 6 | # of edge cases tried in current run seed = -3195058119397656120 | random seed to reproduce generated values
Errors will cause the test to fail and output the failure for you to review.