0

I created the following method that I use to validate Roman numbers converter. In JUnit the test passes but the program doesn't throw any exception. Where did I wrong?

public void validateState(String number){
    if(!number.matches("^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$"))
        throw new IllegalArgumentException("Invalid number");

    System.out.println("Invalid number");
}

Test:

@Test(expected = IllegalArgumentException.class)
public void test15() throws Exception {
    new RomanNumber("").validateState("MMMMM");
}

Thank you for the help.

sinsuren
  • 1,745
  • 2
  • 23
  • 26
InExperience
  • 103
  • 1
  • 3
  • 12

3 Answers3

5

If the test passes, it would mean that the IllegalArgumentException is thrown in your method.
Otherwise, the JUnit test would fail because here you do an assertion that the IllegalArgumentException exception is thrown:

@Test(expected = IllegalArgumentException.class)

Remove @Test(expected = IllegalArgumentException.class) and you would see that the test fails.


Edit to answer to your comment : why I don't see "Invalid number" message

You see the exception with a stacktrace in the output (terminal) if the exception is not caught by any caller object . But as I have just explained in my comment, in your case, you don't see the exception because it is trapped by JUnit (which is a caller object) as you used the expected attribute in the @Test annotation. When you run your method, the JUnit runner intercepts your thrown IllegalArgumentException because the JUnit runner know that it must check that an IllegalArgumentException was thrown.
The JVM writes the exception in the output (the error flow in this case) only if the exception goes back until the top of the call stack( it means that no one in the executed code has caught the exception)

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • is it normal that I don't see the message "Invalid number"? – InExperience Aug 02 '16 at 11:15
  • 1
    @user1526278 How could you see something that is written after the statement that throws exception and terminates execution? The sysout you have there should be rather "valid number" – Krzysztof Cichocki Aug 02 '16 at 11:16
  • @user1526278 That depends on how you run tests. If you are using eclipse you should see "invalid number" by clicking on the green progressbar near the test in the junit tab. Of course the displayed text would be the exception message and stack trace, not the System.out.println after the exception gets thrown. – BackSlash Aug 02 '16 at 11:16
  • @user1526278 Also, don't forget to use braces. In this case, your print statement is ***outside*** the if statement. You wouldn't have been able to even compile that if it was inside. – BackSlash Aug 02 '16 at 11:18
  • You should add braces around the two instructions and reverse the order of the two instructions in order to see the message : `{ System.out.println("Invalid number"); throw new IllegalArgumentException("Invalid number"); }` – davidxxx Aug 02 '16 at 11:19
  • @davidhxxx: thank you david for your suggest. Now I see the message, but this is by System.out.println. The question is, but if I launch an exception why I don't see the message by IllegalArgumentException("Invalid number")? – InExperience Aug 02 '16 at 11:31
  • @InExperience Have a look at the [JUnit docs](https://github.com/junit-team/junit4/wiki/Exception-testing), it looks like you want to use `expectMessage`. – fvu Aug 02 '16 at 11:55
  • @InExperience where and why would you like to see the message ? In a real application, you should log this information with a logging api. You System.out does this job in a some way. In your case, you don't see the exception because it is trapped by JUnit as you used the expected attribute in the `@Test annotation` – davidxxx Aug 02 '16 at 12:59
  • @davidhxxx: I thought that the message ("Invalid number") to appear when the program throw an exception. As when programming in the terminal. – InExperience Aug 02 '16 at 13:55
  • @InExperience too many comments, I edited my answer – davidxxx Aug 02 '16 at 14:16
  • @davidhxxx: ok, now I understand why. I'm new in Java and Test-Driven Development (TDD) approach. Thank you. – InExperience Aug 02 '16 at 14:31
  • @InExperience Glad you have understood. You are welcome. TDD is an excellent approach. Good choice. I practice it too. If I answered to your question, don't hesitate to accept my answer. – davidxxx Aug 02 '16 at 19:09
0

The test must pass, your logic is correct. Your test says it is expecting to throw an exception and it really does. Junit catches the exception, validates it and makes the test pass that's it.

expected = IllegalArgumentException.class 

Remove this line from your @Test annotation and it will start throwing exception.

Adelin
  • 18,144
  • 26
  • 115
  • 175
  • If I delete @Test(expected = IllegalArgumentException.class) the test runs on the others test cases and the compiler jumps what interest to me. – InExperience Aug 02 '16 at 11:24
  • No, don't delete the whole annotation, just "expected = IllegalArgumentException.class " if you want to see errors ! – Adelin Aug 02 '16 at 11:36
  • but my test code is correct? @Test(expected = IllegalArgumentException.class) public void test15() throws Exception { new RomanNumber("").validateState("MMMMM"); } – InExperience Aug 02 '16 at 11:39
  • @ Adelin: of course. But my doubt is why I don't see the message which the IllegalArgumentException sends? Only this one. There is an error in the test code? – InExperience Aug 02 '16 at 11:42
0

You seem to be asking why

public void validateState(String number) {
    if (!number.matches(...))
        throw new IllegalArgumentException("Invalid number");

    System.out.println("Invalid number");
}

does not throw an exception AND print the error message at the same time.

The reason is that when the exception is thrown, it will propagate skipping statements until the exception is caught in an enclosing try ... catch. In this case, the println call will be skipped. This is normal Java behavior ...

If you want the exception to be thrown and the message to be printed, write it like this:

public void validateState(String number) {
    if (!number.matches(...)) {
        System.out.println("Invalid number");
        throw new IllegalArgumentException("Invalid number");
    }
}
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216