TRS
TRS

Reputation: 2097

Testing Exceptions with Nunit

Iam using Nunit for my unit tests and I need to unit test a code which throws exception.My code is simillar to this.

    public class Myclass
    {
        public int Count
        {
            get; set;
        }
        public void Foo()
        {
            try
            {
                if (Count >3)
                {
                    throw new Exception();
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }
    }

   [TestFixture]
  public class TestMyClass
  {
    [Test]
    public void TestFoo()
    {
        var obj = new Myclass();
        obj.Count = 4;
        Assert.Throws<Exception>(obj.Foo);
    }
 }

This give a error like this

  Expected: <System.Exception>
  But was:  null

I found that if I remove the try catch block,unit test passes.But I dont want to change the actual code .Please advise how can I unit test abovementioned code and what is right way of doing it.

Upvotes: 2

Views: 5318

Answers (2)

k.m
k.m

Reputation: 31484

Lee's answer is the correct one, yet I'd like to expand on what you gain by implementing it.

Your design is fine, but not test friendly. The problem is twofold:

  1. You hide your class dependencies behind static method calls (MessageBox.Show)
  2. You depend on concrete implementation (MessageBox) rather than on abstraction

Fixing second issue will make code testable. You'll have to introduce fake object which you'll verify against in unit test (as Lee suggested). Fixing second issue correctly (i.e. by injecting dependency via interface) will also fix first issue.

By introduction of an interface we've done two things:

  1. Abstracted use of message box to general error handler component -- we no longer depend on purely-gui-related MessageBox. Actual error handler still could be a message box, but now it just as well could be custom window, system alert or log message. Your class does not need to know what is it, and now it doesn't (we have separated the concerns).
  2. Introduced dependency of said error handler to tested class -- with this change we have stated loud and clear, "To function correctly, this class needs error handler". This is important information to anyone working with your code later.

Upvotes: 3

Lee
Lee

Reputation: 144206

Since your method swallows all exceptions, you can't use Assert.Throws since no exception is thrown.

If you want to check that an exception is handled in some way you could create an interface:

public interface IExceptionHandler
{
    void Handle(Exception ex);
}

public void WinFormsExceptionHandler : IExceptionHandler
{
    public void Handle(Exception ex)
    {
        MessageBox.Show(e.Message);
    }
}

public class Myclass
{
    private readonly IExceptionHandler handler;

    public Myclass(IExceptionHandler handler) { this.handler = handler; }
    public Myclass() : this(new WinFormsExceptionHandler()) { }
    public int Count
    {
        get; set;
    }
    public void Foo()
    {
        try
        {
            if (Count >3)
            {
                throw new Exception();
            }
        }
        catch (Exception e)
        {
            this.handler.Handle(e);
        }
    }
}

Then you can use a mock in your tests, for example using RhinoMocks you could do:

[Test]
public void TestFoo()
{
    var handler = MockRepository.GenerateMock<IExceptionHandler>();
    var obj = new Myclass(handler);
    obj.Count = 4;
    obj.Foo();

    handler.AssertWasCalled(h => h.Handle(Arg<Exception>.Is.Anything));
}

Upvotes: 2

Related Questions