# JUnit – the Difference between Practice and @Theory

Lately a colleague showed me how to improve JUnit tests written for a distance calculator. Speaking with other developers I found out that the majority wasn’t aware of the undocumented @Theories Runner which can be found in an experimental package in JUnit, so I decided to share this valuable “experiment”.

In contrast to the parameterized JUnit test, the Theories-runner will try out all possible combinations of data points against your test methods marked with the @Theory annotation.

But let’s get your hands dirty. Obviously the first thing to do is run the test with the Theories-runner and declare some data points:

@RunWith(Theories.class) public class DistanceCalculatorTest { @DataPoint static public LatLng es_1 = new LatLng( 49.0060285, 8.4006111 ); @DataPoint static public LatLng es_2 = new LatLng( 49.0060285, 8.4005789 ); @DataPoint static public LatLng es_3 = new LatLng( 49.0060056, 8.4005611 ); ... |

The implementation of the distance calculator should be:

- Commutative,
- Positive semidefinite
- And fullfill the triangle equality

Which can be written down using the following three @Theory annotated test methods (which do not accept null values):

@Theory(nullsAccepted = false) public void distanceIsCommutative(LatLng p1, LatLng p2) { assertThat(distanceCalculator.calculate(p1, p2), is(distanceCalculator.calculate(p2, p1))); } @Theory(nullsAccepted = false) public void distanceIsPositiveSemidefinite(LatLng p1, LatLng p2) { assertThat(distanceCalculator.calculate(p1, p2), is(greaterThanOrEqualTo(0.))); } @Theory(nullsAccepted = false) public void distanceFulfillsTriangleEquality(LatLng p1, LatLng p2, LatLng p3) { assertThat(distanceCalculator.calculate(p1, p2) + distanceCalculator.calculate(p2, p3), is(greaterThanOrEqualTo(distanceCalculator.calculate(p1, p3) - delta))); } |

Sometimes you have to assume preconditions to test specific parts of your implementation. In the following @Theory the assumption is either p1 or p2 is null, which should lead to an IllegalArgumentException when using the calculator…

@DataPoint public static LatLng nullPoint = null; @Rule public ExpectedException distanceCalculatorException = ExpectedException.none(); @Theory public void distanceToNullNotDefined(LatLng p1, LatLng p2) throws Exception { assumeTrue(p1 == null || p2 == null); distanceCalculatorException.expect(IllegalArgumentException.class); distanceCalculator.calculate(p1, p2); } |

It is very simple to add more corner cases. The following snippet adds two representations of the north pole:

@DataPoint static public LatLng north_pole_1 = new LatLng( 90, 10 ); @DataPoint static public LatLng north_pole_2 = new LatLng( 90, 20 ); |

If you add a test which won’t work with the whole data points available (e.g. near the poles in this example) they can be easily filtered out by adding a more complex assumption at the beginning of the test method.

@Theory(nullsAccepted = false) public void runningTowardsThePole(LatLng pt) { // this test does not work at the poles assumeThat(pt.lat, is(allOf(greaterThan(-89.), lessThan(89.)))); ... } |

Just a side note. Rewriting the tests for the distance calculator in fact discovered a bug in the original implementation of the distance calculator using LatLng(-1, -1) as NIRVANA. Thanks again Hauke for teaching me this lesson.

Have fun verifying your code with theories.

##### You may also like...

#### Share this Post

#### Tags

### One Response to “JUnit – the Difference between Practice and @Theory”

Written by Florian Waibel. Published in Categories: EclipseSource News, Editors choice

Hi,

Nice to know this features is (will be) available in JUnit.

Lot of inspiration from QuickCheck (http://www.cse.chalmers.se/~rjmh/QuickCheck/)

in scala : https://github.com/rickynils/scalacheck

may be a java port : https://bitbucket.org/blob79/quickcheck