views:

249

answers:

6

I have a method that is going to the DB so all our JDBC stuff in the DAO method is inside a try/catch block. It is catching SQLException

When I write a test case against this method and if a SqlException occurs then my testcase does not say 'caused an error'. it just goes on its merry way.

However, If I dont catch the SqlException in the DAO method but add throws SqlException to the method instead then my test case says 'caused an error' and shows me the error that happened. (this is what I want).

When I try adding throws SqlException along with the method catching the SqlException then also my test case does not say 'caused an error'.

what is the way around it? one is to have try/catch block inside my test case but even if I do this my Junit test case does not say 'caused an error' though the exception IS posted to standard output.

...but besides that anything else?

My IDE is Netbeans. this is where I run the test cases.

Code:

public class MyDaoClass {
 Connection con;
 public MyDaoClass (Connection connection)
 {
  this.con = connection;
 }


 public SomeObject someMethod (String id)
 {
    try{
  Connection con = this.con;
  CallableStatement cs = con.prepareCall("{call some_sp_name (?)}");
  cs.setString (1, id);
  cs.execute()//imagine an error happens here
  ResultSet rs = cs.getResultSet()
  ...
  ....
  //return SomeObject...
    }
    catch (SqlException e) //If I remove this and add 'throws SQLException to method then everything is ok
    {
     log.error(e.getMessage());//i dont have access to log object in test case
    }

 }
    }

public class MyTestSuite extends TestCase
{
 //populate local connection
 public void testSomeMethod () throws SQLException
 {
  MyDaoClass myd = new MyDaoClass(connection);
  SomeObject s = myd.someMethod("blah");
  assertEquals (s.getFirstName(), "pepe");
 }
}
+2  A: 

JUnit doesn't care what you write to standard output. If the exception leaks out of your method, then JUnit takes notice.

If you catch the exception inside your method, then it's correct behavior for the exception not to come out of your method, because it was (we hope!) handled there. So a passing test is a Good Thing.

What you should be testing for is whether your method is producing the correct result (whatever that may be) even in circumstances when an exception is thrown (and handled).

Carl Smotricz
+1: Well put. I'm not sure why the questioner is testing for an exception if his method is coded not to throw one.
R. Bemrose
i'm looking at tests as pass/fail/caused an error. If exception doesn't come into the test case then result is 'failed'. I might look at failed as if the connections and everything went fine. However, at times that is not the case. sometimes the SP might throw an error..which will cause 'failed' for test case instead of 'caused an error'
pepe
@pepe: So... you're saying that you ignore testcases that "fail", but you pay attention to ones that "cause an error"? That probably means you're using your testcases wrong. Your test fixture being interrupted by an exception is a subset of "failure".
Daniel Pryden
when did I say I want to ignore 'fail'. I just said I want to differenciate between actual fail (where dao method ran fine but i didnt get expected result) and caused an error (where there was an error on the DB side - which I should see)
pepe
If you catch it and don't re-throw it, you won't see it, and that won't change unless you change the method. It's fairly standard to throw an exception in your method and then catch it in the unit test outside, if you want to do that.
Carl Smotricz
+2  A: 

If you add throws SQLException to the method, then you don't have to try-catch it anymore.

And yes, you can catch and throw an exception:

try {
   // some code
}
catch (SomeException e) {
   throw e; 
   // or,
   // throw new SomeOtherException();
}
Kaleb Brasee
yup that works. but want to avoid changing the method. can something be done on the test case side?
pepe
No, you can't do anything on the test case side. If the method is swallowing an exception the caller never knows about it. Doing what Kaleb suggests here is redundant. You should either drop the try-catch or rethrow as another exception type "throw new RuntimeException(e)" (very important to preserve the stack trace and other info by passing the original exception in as a parameter to the constructor of the new exception).
Kris
Yeah, I wouldn't rethrow it as stated above, I would use the SQLException as a parameter in an app-specific exception. I was just answering the question -- yes, it is possible to both catch and throw an Exception. It can be the same exception, or it can be different.
Kaleb Brasee
A: 

that is not the full code is it? the compiler would complain that someMethod is not always returning a value.

If you want to keep the method as is, then at least add "return null;" after the try/catch. That way, if an SQLException occurs, then assertEquals should throw NullPointerException which should work on your TestCase.

Side advice, i would check if connection is not null before using it.

medopal
thats not whole code mate. this is just prototype...i didnt add return statements and stuff. that all is working fine
pepe
+3  A: 

All checked exceptions in Java must be declared in the method specification. SqlException is a checked exception, so if you want to throw it, you must include it in the specification.

If you want to throw an exception, but you can't change the method specification, you need to use an unchecked exception, like RuntimeException. It will also cause JUnit to show the error that happened.

The Java Tutorials: Exceptions is an excellent reference on this topic.

Chip Uni
A: 

Instead of re-throwing the exception, you can also return a null reference instead of an empty or incomplete object. Your callers must check for null's and handle the case when the DAO fails to load the object.

Alternatively, you can stub the log object in your JUnit test and inject it into the DAO via an alternative constructor. Your stubbed logger subclass can deliver the message to your test for inspection.

rsp
then i'll be chekcing for NPE all over my code.
pepe
It is common sense to check object references you get from methods for `null` before you dereference them. Otherwise you will indeed have to check for NPE. Think about what the caller should do when teh DAO fails to load an object. One way or another the caller must know. If you do not throw an exception a return value that can be checked is the way to go. (and my preferred way over using exception handling to pass object state.)
rsp
A: 

In addition to what Chip Uni said above re: Runtime exceptions to not need to be declared, you should also note that exceptions can be nested, i.e.

catch (SqlException e)
{
 throw new RuntimeException(e);
}

This will throw a RuntimeException that contains an SqlExceotion.

crowne