Reputation: 2097
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
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:
MessageBox.Show
)MessageBox
) rather than on abstractionFixing 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:
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).Upvotes: 3
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