views:

539

answers:

8

Hi

I am wondering why should you unit test exceptions? Like I thought you should not be testing code you did not write.

In a sense to me you're not really writing the exception. Sure you put it in a try/catch but should you not assume that the try catch will work and you will catch that exception.

Like for instance I have some GetUser(...) from Asp.net membership. If no user is found it throws a NullReferenceException.

So I just have

try
{
   MembershipUser user = Membership.GetUser(...);
}
catch(NullReferenceException ex)
{
   throw new NullReferenceException()
}

Normally I would just catch the message right there and print out the ex.Message but I need to throw it for unit testing.

So why would I need to test this I assume the try/catch works. So why check if it is thrown?

I am not very good with Exceptions and Unit testing. So maybe I am missing something.

In this case the code is a method that gets called by another method. So in my other method I could surround it with another try/catch and print the ex.Message to the webpage or log file.

But if I had this code in one method and the it gets thrown where would I catch it?

+13  A: 

You want to make sure that exceptions happen when invalid parameters are used, but not when valid parameters are used.

That is why you test for exceptions.

Dan Herbert
+2  A: 

The idea of testing exceptions is not to test if try/catch was implemented properly. It is used to test if you enter invalid parameters (for example), you have control on what will happen.

Also, you are testing if you're giving the proper treatment to it.

Suppose an invalid parameter doesn't raise an exception (when you think it would), or is treating the wrong way. Then your application would be at a invalid state, and maybe this would show up just much later. You would get a bug report, and it would be much harder to track what caused it.

Samuel Carrijo
+20  A: 

You should be testing the contract of your code. That includes:

  • What happens if you give your code invalid data? Does it throw exceptions without corrupting its state? (If it's meant to, of course.)
  • What happens if something you depend on throws an exception? To test that, you'd make a mock object throw an exception, and check that your code still behaves properly.
Jon Skeet
+2  A: 

You don't have to rethrow the exception just to make sure it happens in unit testing. You've picked a particularly difficult example, but generally you want to use mock objects and set up expectations that an exception is thrown and just make sure your code handles it properly. If your code doesn't handle, but rather generates the exception, you would need to test that it throws them under the correct circumstances.

  try
  {
    MembershipUser user = MembershipWrapper.GetUser(...);
  }
  catch(NullReferenceException ex)
  {  
    ... handle exception...
  }

Then have a test similar to:

  public void NoUserTest()
  {
      var mockMembership = MockRepository.GenerateMock<MembershipWrapper>();
      var memberName = ...
      var password = ...

      mockMembership.Expect( m => m.GetUser( memberName ) )
                    .Throw( new NullReferenceException() );

      var myClass = new ClassUnderTest( mockMembership ); // inject dependency

      bool valid = myClass.Validate( memberName, password );

      Assert.IsFalse( valid );

      mockMembership.VerifyAllExpectations();
 }
tvanfosson
A: 

The general concensus is that your code shouldn't catch exceptions it can't handle, so just re-throwing it isn't helping.

In my opinion, you should unit test the exceptions that your code generates in a method. For instance, if you have code like:

public void SomeMethod(SomeClass param)
{
    if (param == null)
    {
        throw new ArgumentNullException("param");
    }
    /* ... */
}

...then the idea is your unit test should have a test case where it passes in a null for param, and verifies that it throws the correct exception. This would happen in test driven development because before you wrote the above code to even check for a null reference, you'd have to write a unit test that tested for the exception being thrown, and that unit test would fail.

If you decide that nobody will ever call your method with a null parameter, and your code generates an ObjectReferenceNotSet... exception if it were ever called with null, then you should test that as well, and test the state of the object after the call to make sure it's what you expect. The reasoning is that some user of your code in the future might (for some really odd reason) be bargaining on the fact that your code throws that exception when they call it with a null reference, and if you changed it, you're changing that contract, and it's supposed to make you think about what that means for all consumers of the method.

Scott Whitlock
I think it's still fairly useful to test a standard exception, just to prove that the exception can occur if you're not careful. If the exception should never occur, then you should handle it inside the function. In this case, since the function is meant to get a user, if the user doesn't exist, I'd either create a new user with that name or I'd return an error message / throw an exception that was nicer than "NullReference".
Adam V
@Adam V - Absolutely, but I was talking more in general. For instance, in an example where a certain input could cause a division by zero, if you knew that could happen, you could test for that case, and instead of performing the division, just return some safe value, or throw an argument out of range exception, etc. In both of those cases you need to write a unit test to check that functionality. If you've decided to let it throw the divide by zero exception, you should test for that too.
Scott Whitlock
+1  A: 

Normally I would just catch the message right there and print out the ex.Message but I need to throw it for unit testing.

This is a mistake. Unit testing is not intended to change your code, it's intended to test the code as it currently exists. So if you would normally catch the message and write the error somewhere, then your unit test should force the exception and ensure the message was written to the proper location.

Adam V
Even when I *can* answer something, Jon Skeet can answer it better. :)
Adam V
A: 

IMO, you write unit testing for assurance that your method will do the right things, with different inputs.

Unit testing exceptions is needed when you want your method to throw an exception, for example, when you pass an invalid parameter for it, and you want it to throw an InvalidArgumentException.

In your example, I don't think unit testing NullReferenceException is needed, since it's not your code under test. But you could test what your method will do if GetUser throws an NullReferenceException (like assert if the exception was logged).

mkato
A: 

You should define a clean layer between the business logic and the view. The business logic should throw the exception, and the view layer catch it and display an appropriate error message.

So, you should be unit testing functions like GetUser to ensure that a. If you ask for a valid user, no exception is thrown. b. If you ask for an invalid user, an exception of the appropriate type is thrown.

This ensures that the logic of GetUser passes these 2 constraints. Of course, 2 data points doesn't mean anything works -- but if it fails, it means that it does not. Testing is an inductive process - you are trying to infer the correctness of the program from tests on selected data points - so it is a falsity preserving transformation, not a truth (deductive) preserving transformation.

As mentioned in an earlier post, you should be throwing a more specific exception for this error. That way you can distinguish between the procedure throwing an exception because the user was not valid, and throwing an exception because you forgot to initialize a variable somewhere.

Larry Watanabe