26

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.

Ankit Dhingra
  • 6,534
  • 6
  • 31
  • 34
  • I've got the same problem. We have unit tests that for the sake of code coverage attempt to induce exceptions from our code. In general I like that our code coverage is high, but all the stack traces in the output is very distracting. Having a built-in feature in junit would be quite nice, especially if you could control the behavior from the annotation. +1 – Mark Kegel Sep 18 '12 at 22:36
  • http://stackoverflow.com/questions/156503/how-do-you-assert-that-a-certain-exception-is-thrown-in-junit-4-tests - Use the ExpectedException Junit rule. – JeeBee Mar 16 '15 at 15:27
  • This irritates me too. – Sridhar Sarnobat Nov 04 '16 at 20:05

6 Answers6

20
<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.

schnatterer
  • 7,525
  • 7
  • 61
  • 80
cbradsh1
  • 493
  • 5
  • 12
5

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 :-)

Matthew Farwell
  • 60,889
  • 18
  • 128
  • 171
  • 1
    Not the best ideology, in my project, many developers have that same mindset but it results that some exception logs were in reality exceptions that shouldn't be generated, but as they thought those logs were "normal" they never cared to review them. – htafoya Feb 10 '20 at 19:42
4

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);
Sridhar Sarnobat
  • 25,183
  • 12
  • 93
  • 106
theferrit32
  • 241
  • 5
  • 7
1

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));
    }
}
-1

One of the things that you can do, is not to use expected exception feature. Sometimes I do this, when there are just too many tests, and I do not want a real exception to get ignored because the maven build has printed expected expectations.

boolean exceptionOccured = false;
try {
    // My test here);
} catch (ExpectedException ex) {
   exceptionOccured = true;
}
if(!exceptionOccured) {
    Asser.fail();
}
Ashish Tyagi
  • 191
  • 3
  • 16
-1

In my case, I am doing an assertNotNull with Thrown exception in the catch block. This way if the reverse happened in the code I will get assertNotNull Failure. And Yes There is nothing to hate about if stacktrace is printed. It has a reason.

//Building the precondition for test case goes here.
try {
    begin();       
    System.out.println("Expected ConstraintViolationException occurred");
    dao.save(myObject);            
    commit();
} catch (Exception e){
    assertNotNull(e);
} finally {
    rollback();
}
Zong
  • 6,160
  • 5
  • 32
  • 46