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

<[email protected]> 12 Mar 2014 17:19:38 -0700
Newsgroups gmane.comp.java.junit.user
Message-ID <[email protected]>
Comrades, 

   Comparing two BigDecimals for the same value shouldn't be done with the equals() method, since two instances that have the same value but a different scale won't be "equal." But there aren't any methods in Assert.class to do this. This means I need to write this:
 

 Assert.assertTrue(expected.compareTo(actual) == 0);
 

 when I would rather write this:
 

 Assert.assertCompare(expected, actual)
 

 The second one has the added advantage that it can throw a ComparisonFailure, so I can see the two values in the test results.
 

 I would like to suggest the following four methods be added to Assert.class:
 

 <T extends Comparable<T> void assertCompare(T, T);
 <T extends Comparable<T> void assertCompare(String, T, T)
 <T> void assertCompare(T, T, Comparator<T>)

 <T> void assertCompare(String, T, T, Comparator<T>)
 

 I have some code that implements these methods. I have this working in a production environment. I use it on BigDecimal values, but it works with any values that implement Comparable, or anything for which you can write a Comparator. 
 

 Here is my proposed code:
 

     /**
      * Compare two Comparable objects using Comparable.compareTo() instead 
      * of equals(). This is most useful for classes for which Comparable is 
      * inconsistent with equals(), such as BigDecimal.
      *
      * @param expected
      *            expected value
      * @param actual
      *            actual value
      * @param <T>
      *            Any object that implements Comparable
      * @see java.lang.Comparable
      */
     public static <T extends Comparable<T>> void assertCompare(final T expected, final T actual) {
         assertCompare(null, expected, actual);
     }
 

     /**
      * Compare two Comparable objects using Comparable.compareTo() instead 
      * of equals(). This is primarily for classes for which Comparable is 
      * inconsistent with equals(), such as BigDecimal.
      *
      * @param message
      *            the identifying message for the {@link AssertionError} (<code>null</code>
      *            okay)
      * @param expected
      *            expected value
      * @param actual
      *            actual value
      * @param <T>
      *            Any object that implements Comparable
      * @see java.lang.Comparable
      */
     public static <T extends Comparable<T>> void assertCompare(final String message, final T expected, final T actual) {
         if (expected == null && actual == null) {
             // okay
         } else if (expected != null && actual != null && expected.compareTo(actual) == 0) {
             // We tested both for null here, because the compareTo method might
             // not handle a null parameter cleanly. (BigDecimal, for example,
             // throws a NullPointerException.) For these cases, it's
             // preferable to throw a ComparisonFailure exception.
         } else {
             failCompare(message, expected, actual);
         }
     }
 

     private static void failCompare(final String message, final Object expected, final Object actual) {
         String cleanMessage = message == null ? "" : message;
         String expectedString = expected == null? null : expected.toString();
         String actualString = actual == null? null : actual.toString();
         throw new ComparisonFailure(cleanMessage, expectedString, actualString);
     }
 

     /**
      * Compare two objects using Comparator.compare() instead of equals(). 
      * This is primarily for classes with a natural order that is 
      * inconsistent with equals(), such as BigDecimal.
      *
      * @param message
      *            the identifying message for the {@link AssertionError} (<code>null</code>
      *            okay)
      * @param expected
      *            expected value
      * @param actual
      *            actual value
      * @param comparator
      *            The comparator used to compare the values
      * @param <T>
      *            The type of the object
      * @see java.util.Comparator
      */
     public static <T> void assertCompare(final T expected, final T actual, final Comparator<T> comparator) {
         assertCompare(null, expected, actual, comparator);
     }
 

     /**
      * Compare two objects using Comparator.compare() instead of equals(). 
      * This is primarily for classes with a natural order that is 
      * inconsistent with equals(), such as BigDecimal.
      *
      * @param message
      *            the identifying message for the {@link AssertionError} (<code>null</code>
      *            okay)
      * @param expected
      *            expected value
      * @param actual
      *            actual value
      * @param comparator
      *            The comparator used to compare the values
      * @param <T>
      *            The type of the object
      * @see java.lang.Comparator
      */
     public static <T> void assertCompare(final String message, final T expected, final T actual, final Comparator<T> comparator) {
         if (comparator == null) {
             throw new IllegalArgumentException("Null Comparator in test");
         }
         if (expected == null && actual == null) {
             // okay
         } else if (expected != null && actual != null && comparator.compare(actual, expected) == 0) {
             // We tested both for null here, because the compare() method might
             // not handle a null parameter cleanly. For these cases, it's
             // preferable to throw a ComparisonFailure exception.
         } else {
             failCompare(message, expected, actual);
         }
     }