3

I am using AssertJ extracting() method with Java8 lambdas and mapping some fields to BigDecimal, then asserting the resulting array. But I need to compare BigDecimal using compareTo() and not with equals() (because of this). How can I do that?

Example:

Actual actual = performTest();

Assertions.assertThat(actual)
  .extracting(
    Actual::getName,   // returns String
    Actual::getValue  // returns BigDecimal
  )
  .containsExactly(
    "abc",                 // ok, String equals comparison
    new BigDecimal("1.1")  // NOT OK, equals comparison, but I need compareTo comparison
  );

Edit: I am looking for a fluent way to do this, because of course I can split this into multiple different Asserts and compare it that way, or put everything in one giant Condition.

Community
  • 1
  • 1
jhyot
  • 3,733
  • 1
  • 27
  • 44

3 Answers3

10

You can use BigDecimalComparator like :

Actual actual = performTest();
Assertions.assertThat(actual)
.extracting(
  Actual::getName,   // returns String
  Actual::getValue  // returns BigDecimal
)
.usingComparatorForType(BigDecimalComparator.BIG_DECIMAL_COMPARATOR, BigDecimal.class)
.containsExactly("abc",  new BigDecimal("1.1"));
Matthieu Gabin
  • 830
  • 9
  • 26
  • 1
    Nice! I think this has been an addition since the question was originally asked. – jhyot Apr 26 '21 at 17:48
  • 2
    This is perfect. However, when using it, pay attention to actually create a new `BigDecimal` like in the example. I was using `BigDecimal.TEN` and it wasn't working, but when creating one from a string value, it worked like a charm. – rafael.braga Jul 12 '22 at 19:18
0

If @assylias's solution doesn't work, you can always use a custom Condition.

 assertThat(new BigDecimal("1.1")).has(new Condition<BigDecimal>() {
        @Override
        public boolean matches(BigDecimal s) {
            return s.compareTo(new BigDecimal("1.1")) == 0;
        }
 });

Wrap it in a functional interface for a nicer syntax.

Edit: Using the tuple extractor in your example:

    assertThat(foo).extracting("name", "value").has(new Condition<Object[]>() {
        @Override
        public boolean matches(Object[] value) {
            return new BigDecimal("1.1").compareTo(value[1]);
        }
    });

Without tuple extractor:

Assertions.assertThat(actual).has(actualValue("abc", new BigDecimal("1.1")));

// Hide this somewhere and import static :)

public static Condition<Actual> actualValue(String expectedName, BigDecimal expectedValue) {
    return new Condition<Actual>() {
        @Override
        public boolean matches(Actual value) {
            return expectedName.equals(value.getName()) && value.getValue().compareTo(expectedValue) == 0;
        }
    };
}
Fabien Benoit-Koch
  • 2,784
  • 2
  • 21
  • 33
  • I don't have a single `BigDecimal` to compare, but the `extracting` part generates something like an Array or Tuple of `(String, BigDecimal)`. How would I write a different `has()` for the String (or just use normal equals here) and for the`BigDecimal`? – jhyot Sep 01 '16 at 12:41
  • In that case, simply change the generic parameter from Condition to Condition. And changes the matches method to take an Object[] as parameter, only using the second item of the array in the compartor. Since it's becoming a bit ugly, you could create an adhoc class for that, so that your test stays a one-liner. – Fabien Benoit-Koch Sep 01 '16 at 12:47
  • Thanks for the edit. That does not compile, I have to cast `value[1]` to BigDecimal. It is getting uglier and uglier ;) – jhyot Sep 01 '16 at 13:04
  • Yeah. I was bored, so i wrote it the cleanest i could, without extractors. Enjoy or ignore :) – Fabien Benoit-Koch Sep 01 '16 at 14:00
  • Thanks for the effort :) – jhyot Sep 01 '16 at 15:47
0

I would use matches if it's a one time assertion:

assertThat(actual).matches(a -> a.getName().equals("abc") && p.getValue().compareTo(new BigDecimal("1.1")) == 0);

If you plan to reuse the assertion, I would create a condition as suggested by @fabienbk.

Joel Costigliola
  • 6,308
  • 27
  • 35
  • Thanks! Because it's actually 1 String and 3 BigDecimals, and it's a one time assertion, I just went for 4 asserts each as their own statement. – jhyot Sep 02 '16 at 17:17