assertThatThrownBy() check field on custom exception
Asked Answered
A

4

25

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

Acetum answered 26/10, 2020 at 16:29 Comment(3)
You can catch the Throwable using catchThrowable and then make whatever assertions you want to on that (after casting to your type if necessary).Laurenelaurens
Nice idea, unfortunately even if I hard cast SomeException throwable = (SomeException ) catchThrowable(() ... extracting() method doesn't take into account fields of SomeExceptionAcetum
I have updated casting exampleAcetum
T
18

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);
Towards answered 27/10, 2020 at 1:2 Comment(7)
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?Acetum
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 adviseAcetum
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.Towards
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 :(Acetum
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 futureAcetum
It is usually ok to use the latest, 3.18.0 at the time of this replyTowards
@Acetum assuming you have a maven project and you are at least on java 8, you can add <assertj.version>3.18.0</assertj.version> 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.Overweight
M
26

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();
Muezzin answered 15/12, 2021 at 17:11 Comment(2)
great advice, nice and clear way to handle it in unit testsDecalescence
This should be the best and accepted answer!Cheatham
T
18

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);
Towards answered 27/10, 2020 at 1:2 Comment(7)
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?Acetum
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 adviseAcetum
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.Towards
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 :(Acetum
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 futureAcetum
It is usually ok to use the latest, 3.18.0 at the time of this replyTowards
@Acetum assuming you have a maven project and you are at least on java 8, you can add <assertj.version>3.18.0</assertj.version> 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.Overweight
T
2

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.

Toadflax answered 2/4, 2021 at 11:49 Comment(0)
K
2

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);
  });  
Kamakura answered 24/1, 2023 at 9:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.