Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ignoring stacktrace when testing for exceptions in Junit

We are testing for exceptions in our unit tests

@Test(expected=IOException.class)
     public void test() {
     // run some code that throws IOException.
}

The test is passing but as a part of the maven build that runs the test, the stacktrace comes in the console output. Is there anyway in which this stacktrace can be ignored in the tests.

like image 373
Ankit Dhingra Avatar asked Feb 21 '12 10:02

Ankit Dhingra


People also ask

How do I cover test case for catch exception in JUnit?

If you want to cover the code in the catch block, your test needs to cause an exception to be thrown in the try block. You will have to setup your test such that it will throw an exception.

How do you handle throwing exceptions in JUnit?

JUnit provides an option of tracing the exception handling of code. You can test whether the code throws a desired exception or not. The expected parameter is used along with @Test annotation. Let us see @Test(expected) in action.

How does JUnit handle checked exceptions?

Since it looks like InvalidRomanNumberException is a checked exception, you have to either surround it with a try-catch or declare that the method throws InvalidRomanNumberException . JUnit or not, this is the norm.

Can we throw exception in JUnit test?

When using JUnit 4, we can simply use the expected attribute of the @Test annotation to declare that we expect an exception to be thrown anywhere in the annotated test method. In this example, we've declared that we're expecting our test code to result in a NullPointerException.


4 Answers

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.7.1</version>
    <configuration>
        <redirectTestOutputToFile>true</redirectTestOutputToFile>
    </configuration>
</plugin>

Place the above code into your pom.xml's plugins section. redirectTestOutputToFile will remove the stacktrace from the console output. Obviously, replace the version of surfire with the version you are using.

BTW the redirectTestOutputToFile parameter is available in the failsafe plugin as well, so you can apply this to your integration tests in the same fashion.

like image 144
cbradsh1 Avatar answered Nov 26 '22 16:11

cbradsh1


There isn't a nice way to do this, and it's not worth it anyway. I assume that the printed stacktrace is coming from the called code, and not from your test code:

public class ExpectedExceptionTest {
  @Test(expected = IOException.class)
  public void test() throws Exception {
    foobar();
  }

  public void foobar() throws IOException {
    try {
      throw new IOException();
    } catch (IOException e) {
      e.printStackTrace(System.err);
      throw e;
    }
  }
}

Here, the stacktrace which appears in the maven build log is coming from the error handling of the method that you're trying to test. You don't want to change this error handling. If the test fails, then you want to know what's happened.

If you change it, then it also complicates the code under test unnecessarily. Apart from this specific test, you always want the stacktrace to appear.

So, can we set System.err to be null, as was suggested elsewhere? No. If you call

System.setErr(null);

Then this will result in a NullPointerException (with the above error handling).

If you use log4j or similar for your logging, then you can have a @Rule which temporarily sets the logging level to INFO so that the exception doesn't appear in your logs. Again, the debug won't appear when you need it most, if the test fails.

I get these exception stacktraces all of the time in my project build output(s). I just accept it and congratulate myself that I'm testing error conditions correctly :-)

like image 40
Matthew Farwell Avatar answered Nov 26 '22 17:11

Matthew Farwell


System.err is what that gets printed to, and it is a PrintStream which can be modified at runtime. So in the System.err, put a new PrintStream made from an OutputStream that prints out nothing when write(int i) is called:

System.setErr(new PrintStream(new OutputStream(){public void write(int i){}}));

Remember to backup the current PrintStream in System.err though after you're done suppressing output, or else you won't receive other errors that might actually be useful to know about.

You can backup and set the fake on in BeforeClass and restore in AfterClass or something like that.


Additional notes:

Here's a fuller set of lines you can put in your test:

java.io.PrintStream realErrorStream = System.err;
System.setErr(new java.io.PrintStream(new java.io.OutputStream(){public void write(int i){}}));
...
System.setErr(realErrorStream);
like image 22
theferrit32 Avatar answered Nov 26 '22 17:11

theferrit32


y solution to assert that I actually catch expected Exception without seeing stacktrace is

@Test
public void test() {
    try {
 // run some code that throws IOException.
    } catch (Exception ex) {
        assertTrue(ex.getClass().equals(IOException.class));
    }
}
like image 30
Maciej Mioduszewski Avatar answered Nov 26 '22 16:11

Maciej Mioduszewski