16

How can I check particular field value in my custom excepiton using assertJ?

Here is exception class:

public class SomeException extends RuntimeException {
    private final Set<Integer> something;

    public SomeException (String message, Set<Integer> something) {
        super(message);

        this.something = something;
    }

    public Set<Integer> getSomething() {
        return something;
    }
}

Here is my test:

    assertThatThrownBy(() -> service.doSomething())
        .isInstanceOf(SomeException.class)
        .hasMessageStartingWith("SomeException has 1,2,3,4 in something field. I want assert that")
        . ??? check that SomeException.getSomething() has 1,2,3,4 ???

The problem is that if I chain extracting() it will think I'm using Throwable. So I can't extract field something

Update:

SomeException throwable = (SomeException) catchThrowable(() -> service.doSomething(

assertThat(throwable)
    .hasMessageStartingWith("extracting() bellow still think we're working with Throwable")
    .extracting(SomeException::getSomething <<<--- doesn't work here)

I have tried following, as suggested bellow:

 assertThat(throwable)
        .hasMessageStartingWith("Works except containsExactlyInAnyOrder()")
        .asInstanceOf(InstanceOfAssertFactories.type(SomeException.class))
        .extracting(SomeException::getSomething)
        .->>>containsExactlyInAnyOrder<<<--- Not working!!!

But I can't use containsExactlyInAnyOrder() anymore :(

Please advise

tillias
  • 1,035
  • 2
  • 12
  • 30
  • You can catch the `Throwable` using `catchThrowable` and then make whatever assertions you want to on that (after casting to your type if necessary). – BeUndead Oct 26 '20 at 16:34
  • Nice idea, unfortunately even if I hard cast SomeException throwable = (SomeException ) catchThrowable(() ... extracting() method doesn't take into account fields of SomeException – tillias Oct 27 '20 at 08:57
  • I have updated casting example – tillias Oct 27 '20 at 09:01

4 Answers4

19

It looks like you're looking for catchThrowableOfType, which allows you to receive the correct class:

import static org.assertj.core.api.Assertions.catchThrowableOfType;

SomeException throwable = catchThrowableOfType(() -> service.doSomething(), SomeException.class);

assertThat(throwable.getSomething()).isNotNull();
jamietanna
  • 263
  • 1
  • 8
  • 21
14

There are quite a few variations on extracting, the one you want to use is extracting(String), ex:

   assertThatThrownBy(() -> service.doSomething())
        .isInstanceOf(SomeException.class)
        .hasMessageStartingWith("SomeException ... ")
        .extracting("something")
        .isEqualTo(1,2,3,4);

Use extracting(String, InstanceOfAssertFactory) to get specialized assertions, so if the value is a collection you can try:

   assertThatThrownBy(() -> service.doSomething())
        .isInstanceOf(SomeException.class)
        .hasMessageStartingWith("SomeException ... ")
        .extracting("something", InstanceOfAssertFactories.ITERABLE)
        .contains();

You can also try: hasFieldOrPropertyWithValue

Update: working example

SomeException throwable = new SomeException("foo", Sets.newSet(1, 2, 3, 4));

assertThat(throwable).hasMessageStartingWith("fo")
                     .extracting("something", InstanceOfAssertFactories.ITERABLE)
                     .containsExactly(1, 2, 3, 4);
Joel Costigliola
  • 6,308
  • 27
  • 35
  • this is close, but there is no such an overloaded method with InstanceOfAssertFactories.ITERABLE :( any ideas how can I cast first example (extracting("something")) to iterable type? – tillias Oct 27 '20 at 05:13
  • I have also tried casting throwable to my custom exception type as proposed in comment to my question, but exctracting() still things I'm working with Throwable instead of custom type. Please advise – tillias Oct 27 '20 at 08:57
  • tiillias I did not suggest to use `asInstanceOf` and you did not try the `extracting` I pointed out, I have updated my answer with some working code. – Joel Costigliola Oct 27 '20 at 09:42
  • many thanks -> I have tried it and as I mentioned I don't have extracting() which accepts such a parameter. I have checked it once again and it seems I have to update library to the newest version. Unfortunately it will be very difficult, cause I have to update spring-boot dependencies then etc. I will mark it as answer, unfortunately I can't use it because of my version of assertj :( – tillias Oct 27 '20 at 09:45
  • yes, please make sure that version of assertJ needed for your code to work is specified in answer. Otherwise it will raise the same question in future – tillias Oct 27 '20 at 09:50
  • It is usually ok to use the latest, 3.18.0 at the time of this reply – Joel Costigliola Oct 27 '20 at 20:31
  • @tillias assuming you have a maven project and you are at least on java 8, you can add 3.18.0 in your properties section to get the updated artifact without upgrading the spring-boot-dependencies version. It should work with both Spring Boot 1.5.x and 2.x. – Stefano Cordio Nov 21 '20 at 21:48
1

I'd do something like :

assertThatThrownBy(() -> service.doSomething())
    .isInstanceOf(SomeException.class)
    .hasMessageStartingWith("SomeException occurred")
    .isEqualToComparingFieldByField(
        new SomeException("", Sets.newHashSet(1,2,3,4)));

This way you don't have to worry about changing the field name in future because you're not hardcoding it anywhere in the assert statements.

dj_1993
  • 93
  • 1
  • 8
0

An alternative to the extracting method would be to catch the exception in matches or satisfies method :

var elements = Set.of(1, 2, 3, 4);

assertThat(throwable)
  .isInstanceOf(SomeException.class)
  .hasMessageStartingWith("...")
  .matches(e -> ((SomeException) e).getSomething().containsAll(elements);    
assertThat(throwable)
  .isInstanceOf(SomeException.class)
  .hasMessageStartingWith("...")
  .satisfies(e -> {
    SomethingException somethingException = (SomethingException) e;

    assertThat(somethingException.getSomething()).contains(1, 2, 3, 4);
  });  
Olivier Boissé
  • 15,834
  • 6
  • 38
  • 56