Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test that an expected exception is being thrown using google-truth?

I just want to test if an exception with a given message is being thrown using google-truth.

Is quite easy to do that using junit using @Test(expected=, but I'm unable to figure out how to do that with truth. There are no samples around ThrowableSubject.

Should I stick with plain JUnit for these kind of tests?

like image 847
Imanol Avatar asked Jul 18 '16 10:07

Imanol


People also ask

How do you test a method that throws an exception?

In order to test the exception thrown by any method in JUnit 4, you need to use @Test(expected=IllegalArgumentException. class) annotation. You can replace IllegalArgumentException. class with any other exception e.g. NullPointerException.

How do I test exceptions in JUnit 5?

In JUnit 5, to write the test code that is expected to throw an exception, we should use Assertions. assertThrows(). In the given test, the test code is expected to throw an exception of type ApplicationException or its subtype. Note that in JUnit 4, we needed to use @Test(expected = NullPointerException.

How do you test an exception case?

To test the exceptions, we should follow the following steps: Create a class to be tested. Create a test case class for testing exceptions. Create a Test Runner class to execute the test case.

How do you use ExpectedException?

Usage. You have to add the ExpectedException rule to your test. This doesn't affect your existing tests (see throwsNothing() ). After specifiying the type of the expected exception your test is successful when such an exception is thrown and it fails if a different or no exception is thrown.


2 Answers

[updated]

The Truth authors recommend using JUnit 4.13/5's assertThrows() mechanism, since this doesn't really need support in Truth. This would look more like:

SpecificException e =      assertThrows(SpecificException.class, () -> doSomethingThatThrows()); assertThat(e).hasMessageThat().contains("blah blah blah"); assertThat(e).hasCauseThat().isInstanceOf(IllegalStateException.class); assertThat(e).hasCauseThat().hasMessageThat().contains("blah"); 

This is recommended over try/fail/catch as it is terser, avoids the "missing fail" problem, and returns an object that can be asserted-on using the ThrowableSubject in Truth.

If you do not have assertThrows(), then please use the try/fail/catch pattern, as this is clear and explicit.

try {   doSomethingThatThrows();    fail("method should throw"); } catch (SpecificException e) {   // ensure that e was thrown from the right code-path   // especially important if it's something as frequent   // as an IllegalArgumentException, etc.   assertThat(e).hasMessage("blah blah blah"); } 

While @Rule ExpectedException and @Test(exception=...) exist in JUnit, these aren't recommended by the Truth team, insofar as they have some subtle (and less subtle) ways you can write tests that pass but which should fail.

While this is also true of try/fail/catch, internally Google mitigates this with the use of error-prone, which provides a static compile-time check to ensure that this pattern doesn't omit the fail(), etc. It is highly recommended that you use error-prone or another static analysis check to catch these. Sadly, the rule-based and annotation-based methods aren't as easily amenable to static analysis as this try/catch block.

like image 187
Christian Gruber Avatar answered Sep 25 '22 12:09

Christian Gruber


As an update here, we've moved away from the pattern Christian described, and Issue #219 has been closed in favor of JUnit's expectThrows() (coming in 4.13, similar methods already exists in TestNG's Assert).

In tandem with expectThrows() you can use Truth to make assertions about the thrown exception. So Christian's example would now be:

SpecificException expected = expectThrows(
    SpecificException.class, () -> doSomethingThatThrows());
assertThat(expected).hasMessageThat().contains("blah blah blah");
like image 26
dimo414 Avatar answered Sep 24 '22 12:09

dimo414