views:

69

answers:

3

Hi all,

I am just starting out with unit testing and have a scenario I'm not sure how to appraoch and my solution doesn't feel right.

I have a bit of code that does something, if it fails i.e. throws an exception the exception is caught and logged as below.

 public T CreateTypedObjectInstance<T>()
 {
     T o = default(T);
     try
     {
         o = Activator.CreateInstance<T>();
     }
     catch (Exception ex)
     {
         LogError(ex);
         throw ex;
     }
     return o;
 }

 private void LogError(Exception ex)
 {
     if (logger != null)
     {
        logger.LogError(ex);
     }
 }

I want to test that if an error is thrown it calls the LogError() method which in turn calls another object.

I have approached this using a mock for the logger and catch the first exception thrown and then assert the LogError method was called. However, this doesn't feel right needing to catch an exception? I remeber read something that it is bad to have try catches in tests? Are there any other way to perform this test or should I refactor the logic? Any ideas would be great!

      [Test]
    public void CreateTypedObjectInstance_GivenTypeWithoutPrivateContructor_LogErrorToLogger()
    {
        //Setup Method used
        MockRepository mockery = new MockRepository();
        ILogger mockedLogger = mockery.StrictMock<ILogger>();
        genericObjectFactoryInstance.Logger = mockedLogger;
        Expect.Call( delegate { mockedLogger.LogError(null); } ).IgnoreArguments();
        mockery.ReplayAll();
        // this will throw an error as String does not have a parameterless constructor
        try
        {
            genericObjectFactoryInstance.CreateTypedObjectInstance<String>();
        }
        catch { /*ignore this error to test behaviour after*/ }
        mockery.VerifyAll();
    }

EDIT

Using Mark Rushakoff answer the test becomes and works like a charm.

        [Test]
    public void CreateTypedObjectInstance_GivenTypeWithoutPrivateContructor_LogErrorToLogger()
    {
        //Setup Method used
        MockRepository mockery = new MockRepository();
        ILogger mockedLogger = mockery.StrictMock<ILogger>();
        genericObjectFactoryInstance.Logger = mockedLogger;
        Expect.Call( delegate { mockedLogger.LogError(null); } ).IgnoreArguments();
        mockery.ReplayAll();
        Assert.Throws<MissingMethodException>(() => genericObjectFactoryInstance.CreateTypedObjectInstance<String>());
        mockery.VerifyAll();
    }
+2  A: 

The unit test can actually check if the exception is thrown when the exception condition is met. For example:

Method:

public int getCalc(int a, int b) throws SampleException {
   if (a > b) {
      throw new SampleException();
   }
   // (..)
}

Test:

public void testGetCalcException() {

   try {
     getCalc(2,1); // 2 > 1  exception is expected
     fail("SampleException was expected but was not thrown");       

   } catch(SampleException e) {
      // great - test passed!
   } 

}
Bruno Rothgiesser
I was just typing almost the same thing. Good answer!
Paul
+4  A: 

You didn't say what version of NUnit you're using, but the preferred approach would be the Assert.Throws method.

Assert.Throws<YourCustomException>(() => GenericObjectFactoryInstance.CreateTypedObjectInstance<String>());

@Bruno's answer is appropriate when your testing framework does not offer a facility to check for thrown exceptions.

Mark Rushakoff
TrueWill
A: 

If you are using NUnit as your ut testing framework, you can use the ExpectedException attibute to check if the method actually throws the expected exception or not. this approach does not require you to have try and catch blocks within the test code.

You can look at the following example for more details ExpectedException example

Nilesh Gule
Using ExpectedException is pretty much deprecated now. Assert.Throws is preferable, as it's less error prone.
Mark Simpson