• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Catch thrown exception in Junit without Throwable block swallowing it

 
Ranch Hand
Posts: 85
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I have a class that divides two numbers. When a number is divided by 0, it throws ArithmeticException. But when I unit test this, on console it is showing that ArithmeticException is thrown, but my test is failing with an AssertionError. I want to know if there is a way to prove that it is throwing ArithmeticException in Junit?

Example.java

ExampleTest.java


My actual code is different, since that has lot of dependencies, I simpflied my requirement to this example test. Please suggest.
 
Marshal
Posts: 28193
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Your test says "The divide method is going to throw an ArithmeticException in this case". But it doesn't throw an ArithmeticException and therefore the test fails.

Now, if you removed the code which catches the exceptions and allow them to be thrown by the method, then your test would pass.

But perhaps you're going to say "But it DOES throw an ArithmeticException"? Remember that a JUnit test doesn't (or shouldn't) care what happens inside the method it's testing. It only cares about the result.
 
swathi bairu
Ranch Hand
Posts: 85
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Paul Clapham wrote:
Now, if you removed the code which catches the exceptions and allow them to be thrown by the method, then your test would pass.




like I mentioned in my comments, this is just an example code I wrote to make you understand my requirement. But, in my actual code, I need to catch that exception in my class and unit test the same.

The following solution helped for my requirement.

 
Paul Clapham
Marshal
Posts: 28193
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
So you want a method to handle that exception, and you want to use JUnit to confirm that the method did indeed handle it? I'm just asking again because that's not a suitable condition for JUnit to test, and in fact it isn't a suitable condition to test at all. Tests should treat the method being tested as a "black box"... you have no idea what the method is doing, all you are concerned with is whether it returns what it's supposed to return, or changes whatever instance-level or class-level variable it's supposed to return.

Or let's look at it another way: could you post the Javadoc for the method which states that it will handle a particular exception under certain conditions? I've never seen Javadoc which says anything like that because, as I said, that isn't a suitable requirement for a method.
 
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I would say that differently.

There are many tests that don't treat the classes/methods under test (CUT/MUT) as black boxes but rather white boxes. That is, the tests have intimate knowledge about details of the CUT's implementation. For example, when you use mock objects to simulate what the CUT's collaborators would be called upon to do, then you are writing a white box test. These are not necessarily unsuitable tests. I write white box tests as I develop the functionality inside my classes incrementally while doing TDD.

White box tests are, however, more brittle since any change to the implementation of the CUT has the potential to cause a corresponding change in the test code. Black box tests are at a higher level of abstraction than white box tests and are more resilient to implementation detail changes in the CUT. Black box tests specify the API of the CUT.

In short, white box tests become detailed implementation design specs that should give you an idea of how the CUT is implemented. Black box tests are detailed API specs that give you an idea of how the CUT API is supposed to be used and how it behaves as far as client code is concerned.

You should keep white box and black box tests separate. Ideally, you would keep them in separate test classes, e.g. MyClassTest (API specs, black box tests) and MyClassImplTest (implementation specs, white box tests)

For example, a list of JUnit test cases for ArrayList might look like this:

These are just a "for instance" - I don't know if ArrayList actually has these unit tests.

That said, it's conceivable that you can write a white box test that specifies that a certain type of exception should be handled inside the method and not be thrown by the CUT. If you're using JUnit 4.x, you should be able to use an @Rule with the ExpectedException class, an example for which is given in the JUnit API documentation here: http://junit.org/javadoc/latest/org/junit/rules/ExpectedException.html

One case where it might be appropriate to test that an Exception is not thrown is when the CUT is a subclass that overrides some behavior of its superclass. For example, one of the methods that ArrayList overrides is the AbstractList.add(). AbstractList.add() throws an UnsupportedOperationException whereas ArrayList.add() does not. It's conceivable that you would write a test to explicitly document this behavior. I would still classify this as a black box test though since it has to do with what a client may or may not expect to see when invoking the ArrayList API. That is, the test code only shows usage of the API and no intimate knowledge of what actually goes on inside the add method.

Again, refer to the JUnit API documentation for ExpectedException for an example.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Another case where it might be appropriate to test that a certain exception should not be thrown is when a CheckedException is wrapped in a RuntimeException. This is a very common approach, especially when you are using Spring. It's not uncommon to wrap SQLExceptions with some kind of Application exception to throw out from a DAO with the intent of letting a domain or service layer class decide whether or not to handle the Application exception rather than be forced to declare the low-level checked SQLException in the signatures of all methods that are in the execution path.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I think I misunderstood this whole thread: OP's intent and Paul's point.

After reading OP's solution, it seems a bit smelly to add a package private method just so you could put a test shunt on it. I would have to agree with Paul in that it doesn't seem appropriate in this case to test for the ArithmeticException from outside of the CUT, i.e. in a black box test. For one, I would question the need to test for an ArithmeticException. I would say figure out what your API is, then write the test to tell that story.

This is one case where the requirements should trigger a thorough questioning of the API design rather than writing a kludge so that the "test requirements" that were given to the programmer are met. As programmers, we also have a duty to THINK and ask WHY a piece of code is difficult to test. One answer might be that it needs to be refactored to make it more testable. Adding a package private method that can be shunted by a test is not a good refactoring. It is a kludge, IMO.

Another answer, which I think is the right one in this case is that the API is not designed properly. I don't think that returning a 0 as a result of divide by zero error is appropriate. And unlike for Double and Float, there is no constant to represent NaN for Integer and Long.

In this case, a 0 denominator is the only time you'll get an ArithmeticException. If you have a divide method and you pass in a denominator value of 0, the method really should throw an IllegalArgumentException, IMO, to indicate that 0 is not an acceptable denominator. This makes a definitive statement that the API for divide does not accept a 0 denominator because there is no sensible return value that can be calculated.

You could also just let the ArithmeticException be thrown without catching it, in which case you are probably assuming that thorough integration testing will reveal any bugs that are caused by not checking the denominator value to ensure that it is not 0 before calling the divide method. Either way is fine but I would still prefer IllegalArgumentException because that is a more definitive statement that there was an API contract violation.

Now, since OP says that he posted simplified code because there are a lot of other dependencies in the actual code, again I'd have to lean on the side of calling a "code smell".

Classes should adhere to SOLID, in particular, Single Responsibility Principle (the S in SOLID). If you have a divide operation that you need to test, then that should be easily isolated and tested. If it's not easily isolated and tested, then you probably have methods that are doing too much in one place, thus violating SRP, are too big thus violating the 4th rule of Simple Design which is that methods should be small, or both. I would bet that the actual method being tested has these smells so my recommendation would be to clean the code up first, then figure out how to test cleanly.
 
Paul Clapham
Marshal
Posts: 28193
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:Now, since OP says that he posted simplified code because there are a lot of other dependencies in the actual code, again I'd have to lean on the side of calling a "code smell".



Yes, but... we're only told that this is "simplified" code. I find it hard to believe that there's a more complicated version with a lot more dependencies, but there's still a method which simply divides one number by another. I believe that there's a method in this complicated version which does something which involves catching an exception, but I suspect that the "something" is actually something other than dividing one number by another.

And if that's the case, one might look at what the method actually does and decide that catching the exception inside the method is a legitimate thing to do in this particular case. Or not. And one might decide that white-box testing was appropriate (thank you for elaborating on the difference between white-box and black-box testing, by the way) in this particular case, or not. It's true that catching an exception and returning some default value can be a code smell, but there are, um, exceptions to that. One would really have to see the actual requirements for that discussion to take place.
reply
    Bookmark Topic Watch Topic
  • New Topic