3

So, I need to write a test for some (legacy) code I'm improving. In a method, I try to parse some string (which should be legal JSON). Then a possible JSONException is caught if the string doesn't represents valid JSON. Something like:

public void transformToJSON(String source) {
  try {
    JSONObject js = new JSONObject(new JSONTokener(item.getHtml()));
  }
  catch (JSONException e) {
    log(e)
  }
  //than js is added to an Hashset and the method is done
}

So I want to write a test for good input (to see if I have generated a correct JSON-object). This is 'easy' by checking the object in the Set.

For wrong input however, I need to find out if the correct error has been thrown. I know if an error was thrown in the code, I can check for it in the test.

  • By setting the rule public ExpectedException thrown= ExpectedException.none(); and checking for it in test method.
  • By adding @Test(expected = JSONException.class) above the test

But both wont work for try..catch blocks.

How can I test if the proper exception is caught by catch block? I want to change as little of the source code as possible.

Sander B
  • 98
  • 1
  • 10
  • It all depends on what the `log(JSONException)` method does since you want to verify that it was called when you expected. The best way to verify that would be to use a test double and verify the call, for instance using Mockito, [but you'd have to be prepared to inject the logger to allow replacing the real logger in tests](http://stackoverflow.com/q/9841623/1240557). – kryger Dec 23 '15 at 15:25

5 Answers5

4

In the JUnit test class you can do is use fail("this should not have happened") in the try or catch block depending on what should and should not work (as in: try and catch in the JUnit class, not in your actual method!).

However, with a try/catch block within your method you cannot see whether an Exception occured or not, because it is handled within the method. So you would have to throw the exception in the method instead of catching it, i.e.,

public void transformToJSON(String source) throws JSONException { ... }

Then it will work to check whether an exception occured or not.

Alternatively you could return a boolean that states whether the transformation was successful or not. Then you can test whether the return value was true/false and if that was what you expected.

public boolean transformToJSON(String source) {
  boolean success = true;
  try {
    JSONObject js = new JSONObject(new JSONTokener(item.getHtml()));
  }
  catch (JSONException e) {
    log(e)
    success = false;
  }
  //than js is added to an Hashset and the method is done
  return success;
}

In your test class:

@Test
public void testTransformToJSON() {
      assertTrue(transformToJSON("whatever"));
}
LordAnomander
  • 1,103
  • 6
  • 16
  • Thank you for the note on the fail-statement, it might be handy in the future. However, I don't really want to 'just throw' an exception, because more than one JSONException is thrown in the method and they need to be handled (they are logged extensively) differently. – Sander B Dec 23 '15 at 14:55
  • @SanderB I made an edit on how you could possibly test whether an exception occured or not. – LordAnomander Dec 23 '15 at 14:56
  • Nice idea, but I can't just change a method return parameter from void to boolean (I might have oversimplified it a bit, it is actually very complex code). However, it is a rather simple test and I don't expect it to change after I'm done with it. (The method needs to be declared public just for testing anyway) So I think this answer is the one I'm going for (unless some advanced JUnit test method comes up) – Sander B Dec 23 '15 at 15:02
2

Based on the logging being used in the code, you can use Mockito to verify the message logged inside catch block.

Please go through the following link for more details on setting up the unit tests

http://bloodredsun.com/2010/12/09/checking-logging-in-unit-tests/

shivdim
  • 81
  • 3
  • Wow, very good! This is the most useful in my situation, and I had no clue it existed! However, I'll stay with the solution of tbrown because it's the most universal (maybe people are looking for an answer that don't use logging in a throw case). But thank you very much for looking it up! – Sander B Dec 24 '15 at 08:28
0

Your legacy code is swallowing the Exception. If it throws an exception, then your junit @Test ( expected = JSONException.class) would work.

Steve O
  • 40
  • 4
  • I know, the point is I don't want to throw an exception. Exceptions are logged extensively, and more than one JSONexception is thrown (one for JSONArray and one for JSONObject) so I need to catch them right away. Thanks for answering though! – Sander B Dec 23 '15 at 14:51
0

I'd change the code slightly so it is

public void transformToJSON(String source) {
  try {
     JSONObject js = getJSON(item.getHtml()));
  }
  catch (JSONException e) {
     log(e)
  }
  //than js is added to an Hashset and the method is done
}

public JSONObject getJSON(String source) throws JSONException {
  return new JSONObject(new JSONTokener(source));
}

and then test against getJSON. This throws an exception and as other have said (and you) you can use the expectedException in the test class

RNJ
  • 15,272
  • 18
  • 86
  • 131
0

use a bad formatted json string, and then do assertions or whatever in the catch block of ur test.

@Test
public void shouldCatchException(){
    String source = "{ \"name\":\"John\", \"age\":30, \"car\":null ";
    try {
        jsonHelper.transformToJSON(source);
    }catch (JSONException e){
        Assert.assertThat(e, notNullValue());
        assertTrue(StringUtils.isNotBlank(e.getMessage());
        //whatever else u need to assert 
    }
}
No-Det
  • 3
  • 2
esteban
  • 96
  • 3