Re: Asserts using Comparable.compareTo() instead of equals() (for BigDecimal and others)

Miguel Muñoz <[email protected]> Sat, 15 Mar 2014 11:35:41 -0700
Newsgroups gmane.comp.java.junit.user
Message-ID <[email protected]>
Comrades,

  Okay, I checked out the conversations at https://github.com/junit-team/junit/issues/95 and https://github.com/junit-team/junit/pull/376, and while I'm not entirely convinced that hamcrest is the way to go for comparison assertions, I can certainly live with it. So I began searching the JUnit classes for an appropriate hamcrest Matcher that would work with BigDecimal values. I looked in these packages and classes:

org.junit.matchers.JUnitMatchers
org.junit.internal.matchers
org.hamcrest.CoreMatchers
org.hamcrest
org.hamcrest.core
org.hamcrest.internal

I couldn't find any classes that helped me compare two BigDecimal values.

Of course, I could search for a Matcher that doesn’t ship with JUnit, or I could write my own Matcher, but a class like BigDecimal, which shipped with version 1.0 of the JDK, should be supported by JUnit out of the box. Here’s why:

Some of the comments had questions like this:

  What makes you think Comparable assertions are common?

I'm going to guess here that the questioner does not work in financial services.

My first Java job was back in 1997 with Java 1.1, before the collections framework was added, and frankly, I never needed BigDecimal until last year, when I started working in the Financial Services industry. My current project is an accounting package, so I use it every day. Our application uses BigDecimal 7714 times, including 4046 times in unit tests. And we're hardly the only developers doing financial services work. So in certain industries, comparisons using Comparable are very common. (If you're writing software for financial services and you're not using BigDecimal, you're creating needless headaches for yourself.)

 I should also point out that standards are more rigorous in financial services, so we tend to write more unit tests. 

Although, given how rarely I used it before I joined this industry, I can certainly understand why non-financial developers would think of BigDecimal as an obscure class that doesn't get used much. But they're wrong.

If BigDecimal were just a useful class from some apache project, I wouldn't be making this case, but BigDecimal and the Comparable interface are completely standard Java, and are used heavily.

So, while I won't try to persuade anyone that a new assertion should be written, I would like to suggest that maybe JUnit should support BigDecimal values out of the box. Perhaps some Matcher classes to support Comparables could be added to org.junit.matchers.JUnitMatchers. 

I would be very happy with this proposed syntax, suggested in the threads I mentioned above:

assertThat(expected, is(comparableTo(actual)));
assertThat(expected, is(greaterThan(actual)));
assertThat(expected, is(lessThan(actual)));
assertThat(expected, isNot(greaterThan(actual))); // for <=
assertThat(expected, isNot(lessThan(actual)))     // for >=

although I'm flexible on this point.

The comparableTo() method could use some discussion about the best name. I don’t want it to say “is(equalTo())” to avoid confusion with the equals() method, and I’d rather avoid something like “numericallyEqualTo” because this shouldn’t be limited to numbers. I’m open to suggestions, but I’ve considered these:

is(naturallyEqualTo( ))  (To invoke the concept of a “natural order” from the Comparable interface)
is(equivalentTo( ))
is(comparableTo( ))
is(comparableValueTo( ))
is(matchingValueWith( ))
is(valueMatching( ))
is(sameValueAs( ))
is(orderedAs( ))
is(theSameValueAs( ))
is(coequalTo( ))
is(coequalWith( ))

I’m sure if we put our heads together, we can come up with something good. 

But that’s all just details. What we really need to discuss is whether we want support for Comparable comparisons out of the box.

— Miguel Muñoz