Java test with expected = exception fails with assertion error

11,954

Solution 1

You are catching the exception and therefore it is not being thrown.

If your intent is to test that you are capturing the exception and relaying it back to the 'user' properly, you should create tests for that specifically. You probably don't want UI elements in your unit tests* so this is a place where abstraction and DI have a lot of value. One simple approach is to create a mock object that will listen for the error message and mark a flag when the message is received. Your unit test trigger the error and then pass if the flag is set. You should also have a negative test or assert that the flag is not set prior to throwing the exception.

*Testing the UI is also a good idea but it can be a little slow. There are various tools for automating that. It generally falls in to a different phase of testing. You really want the unit tests to be really fast so that you can run them very frequently.

Solution 2

You have written production code that simply isn't testable. And more specifically: this code doesn't have any "programmatically" observable side effects in the first place.

Meaning: when you write "production code", the code within a method can do three things that could be observed:

  1. Make method calls on objects that are fields of the class under test
  2. Return some value
  3. Throw an exception

For each of these options, you might be able to write testing code:

  1. Using dependency injection, you can put a mocked object into your class under test. And then you can check that the expected methods are invoked on your mock object; with the parameter that you would expect.
  2. You compare the result you get from calling that method with some expected value
  3. You use expected to ensure that a specific exception was thrown

When you look at your code; you can see: it does none of that. It only operates on objects that are created within the method. It doesn't return any value. And, most importantly: it doesn't throw an exception!

Long story short: a caught exception isn't "leaving" the method. It is caught there, and the method ends normally. The fact that you print details about the caught exception doesn't change that.

So, the first thing you have to do: remove the whole try/catch from your production code!

And, if you want to have a more specific test, you can do something like:

@Test
public void testException() {
  try { 
    new MWE().throwMalFormedURLException();
    fail("should have thrown!");
  } catch ( MalFormedURLException me ) {
    assertThat(me.getMessage(), containsString("whatever"));
  }

The above:

  1. fails when no exception is thrown
  2. fails when any other exception than MalFormedURLException is thrown
  3. allows you to check further properties of the thrown exception
Share:
11,954
DaveM
Author by

DaveM

Freedom like a tumbleweed

Updated on June 14, 2022

Comments

  • DaveM
    DaveM almost 2 years

    I'm having an issue with a test case.

    The method being tested has a try / catch that catches a MalformedURLException but during testing I get a failure due to a Junit AssertionError that expects a MalformedURLException. But I can't find out what it is actually throwing! Here is my code (created as a MWE in eclipse).

    My method that I want to test

    public void throwMalFormedURLException(){
    
        String s = new String("www.google.com");
    
        try{
            url = new URL(s);
        }catch (Exception e){
            e.printStackTrace();
            e.getClass();
            e.getCause();
        }
    
    
    }
    

    the test method

    @Test (expected = MalformedURLException.class)
    public void testThrowMalFormedURLException() {
        MWE testClass = new MWE();
        testClass.throwMalFormedURLException();
        System.out.println("End of test");
    }
    

    This is the output in the console

    End of test error details are: java.net.MalformedURLException: no protocol: www.google.com
    at java.net.URL.(URL.java:593)
    at java.net.URL.(URL.java:490)
    at java.net.URL.(URL.java:439)
    at MWE.throwMalFormedURLException(MWE.java:12)
    at testMWE.testThrowMalFormedURLException(testMWE.java:12)

    In the Junit console it says :

    java.lang.AssertionError: Expected exception: Java.net.MalformedURLException

    But the Junit is reporting failure, even though the console is telling me I've got a MalformedURLException.

    What am I doing wrong with this test ?

    Thanks for your thoughts.

    David