简体   繁体   中英

Delaying a thrown exception to add a soft assertion instead

Consider I have a method to test, which

  • may have side-effects (like files created on the file system), and
  • may throw an exception.

Some of the side effects can be observed (and tested) even when the exception is thrown. My sample test code is below:

final SoftAssertions softly = new SoftAssertions();

try {
    /*
     * May throw an exception
     */ 
    doSmth();
} catch (final IOException ioe) {
    /*
     * How do I add a soft assertion wrapping an exception?
     */ 
}

/*
 * Testing for side effects.
 */
softly.assertThat(...).as("%s exit code", ...).isEqualTo(0);
softly.assertThat(...).as("the number of downloaded files").isEqualTo(3);
softly.assertThat(...).as("this should be true").isTrue();
softly.assertThat(...).as("and this should be true, too").isTrue();

softly.assertAll();

Question 1

What is the best way to create yet another soft assertion out of the exception thrown? With the raw TestNG API, I could write simply

softly.fail(ioe.toString(), ioe);

but AssertJ doesn't seem to provide anything similar. So far, my best option is adding smth like this to the catch block:

softly.assertThat(true).as(ioe.toString()).isFalse();

Are there any better alternatives?

Question 2

How do I make exception(s) thrown by my code being tested, appear as a cause (or suppressed exceptions) of the resulting AssertionError ? Currently, I do the following:

Throwable failure = null;
try {
    doSmth();
} catch (final IOException ioe) {
    failure = ioe;
}

try {
    softly.assertAll();
} catch (final AssertionError ae) {
    if (failure != null) {
        if (ae.getCause() == null) {
            ae.initCause(failure);
        } else {
            ae.addSuppressed(failure);
        }
    }
    throw ae;
}

-- but a more elegant version is much appreciated.

for question 1 Xaero suggestion works fine.

For addressing both questions though, try using catchThrowable combined with fail(String failureMessage, Throwable realCause) (or the one for soft assertions ).

If you have caught a non null throwable (which means that the code under test did throw an exception) you can then use fail to build an AssertionError with a custom error message and pass the caught exception as the cause of the AssertionError .

The code would look like:

Throwable thrown = catchThrowable(() -> { doSmth(); });

if (thrown != null) {
  softly.fail("boom!", thrown);
} else {
  softly.assertThat(...).as("%s exit code", ...).isZero();
  softly.assertThat(...).as("the number of downloaded files").isEqualTo(3);
  softly.assertThat(...).as("this should be true").isTrue();
  softly.assertThat(...).as("and this should be true, too").isTrue();
}

The code above makes me a bit uncomfortable though because it is testing two different scenarios, one when there is an exception thrown and another when there is none. It might be a good idea to create two test cases which will simplify both the test and the assertions part (I believe).

Anyway, hope it helps!

ps: note that you can use isZero() instead of isEqualTo(0)

Question 1 : You can use assertThatThrownBy for this:

softly.assertThatThrownBy(() -> doSmth())
    .isInstanceOf(Exception.class)
    .hasMessage("My Message");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM