assertThrows(myObject).methodCall()

Thomas Mueller <[email protected]> Thu, 7 Jul 2011 22:10:25 +0200
Newsgroups gmane.comp.java.junit.devel
Message-ID <CAKpgiBa4umXFQJH18K4WTt1YCSGSkOu_fde0ra8ARxB7HppSpg@mail.gmail.com>
Hi,

I have many test cases that expect an exception to be thrown. I want
to verify that a given method of my code will actually throw an
exception in a given test case. What I want is described here:
http://stackoverflow.com/questions/156503/how-to-assert-that-a-certain-exception-is-thrown-in-junit4-5-tests
- Example (please not my actual use case isn't ArrayList - this is
just an example):

List<String> myObject = new ArrayList<String>();

// current pattern - 6 lines of code
try {
   myObject.get(0);
   fail();
} catch (IndexOutOfBoundsException e) {
   // expected
}

Now, I have a few problems with this. First, it's 6 lines of code,
which is a lot. Then, it's too easy to forget 'fail()' (I forgot it in
many cases). I know I could refactor the test to move it to a separate
method, and add @Test(expected=IndexOutOfBoundsException.class) (the
top answer on StackOverflow) - but that's ugly as well. I don't _want_
a separate test method.

I found a solution to simplify the test, by creating a new helper
method 'assertThrows' (implementation below), so that my test case is
now:

// shorter, 1 line
assertThrows(IndexOutOfBoundsException.class, myObject).get(0);

// even shorter (if I don't care what kind of exception)
assertThrows(myObject).get(0);

My solution currently uses a Java proxy (which obviously only works
for interfaces), but using CGLIB it would be possible to support
(non-final) regular classes as well. Anyway, for reference, my
solution is here:
http://h2database.com/p.html#554bf1f041969cba0f6fa1a6e8e20cba - my
solution checks that a method was called by miss-using finalize, which
is OK for my use case (there are probably better solutions for this).

I know there are other solutions. I do know this has been discussed
before on the JUnit list:
http://old.nabble.com/assertNotEquals-and-assertThrows-td3423551.html

I also know that JUnit 4.7+ has "Rules" but I really don't want to
write one method for each test. It's ugly because it forces me to
split a test into many tiny methods. I don't like this. For example, I
have test code like this:

assertThrows(stat).execute("select sum(id) from test for update");
assertThrows(stat).execute("select distinct id from test for update");
assertThrows(stat).execute("select id from test group by id for update");
assertThrows(stat).execute("select t1.id from test t1, test t2 for update");

Every *line* would have to be in it's own method.

I have the feeling my feature request will reject it because it would
force JUnit to include a proxy mechanism like CGLIB (which I guess
isn't included now; maybe I'm wrong). And you will probably it's a bit
hacky (well, it is). But it *is* very useful (at least in my view).

I have already submitted this request to Mockito, but they are not
interested that much - they wrote this feature is something that JUnit
is supposed support, as it's not that much related to what Mockito
does.

So, what do you think?

Regards,
Thomas

------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security 
threats, fraudulent activity, and more. Splunk takes this data and makes 
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2