使用Nunit测试异常

时间:2014-06-24 10:18:06

标签: c# unit-testing exception nunit

我使用Nunit进行单元测试,我需要对一个抛出异常的代码进行单元测试。我的代码与此类似。

    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);
    }
 }

这会产生这样的错误

  Expected: <System.Exception>
  But was:  null

我发现如果删除try catch块,单元测试就会通过。但我不想更改实际的代码。请告诉我如何对上述代码进行单元测试以及正确的方法。

2 个答案:

答案 0 :(得分:3)

Lee's answer是正确的,但我希望通过实施它来扩展您获得的收益。

您的设计很好,但不测试友好。问题有两个:

  1. 隐藏静态方法调用(MessageBox.Show
  2. 后面的类依赖项
  3. 您依赖具体实施(MessageBox)而不是抽象
  4. 修复第二个问题会使代码可测试。你必须在单元测试中引入你将验证的假对象(正如李建议的那样)。正确修复第二个问题 (即通过接口注入依赖关系)也将解决第一个问题。

    通过引入界面,我们做了两件事:

    1. 将消息框抽象用于常规错误处理程序组件 - 我们不再依赖纯粹与gui相关的MessageBox。实际的错误处理程序仍然可以一个消息框,但现在它也可以是自定义窗口,系统警报或日志消息。你的班级不需要知道它是什么,现在它没有(我们已经分开了关注点)。
    2. 将所述错误处理程序的依赖性引入测试类 - 通过此更改,我们已经声明清楚,“要正常运行,此类需要错误处理程序”。对于以后使用您的代码的任何人来说,这都是重要的信息。

答案 1 :(得分:2)

由于您的方法吞没了所有异常,因此不能使用Assert.Throws,因为不会抛出任何异常。

如果要检查是否以某种方式处理了异常,可以创建一个接口:

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);
        }
    }
}

然后你可以在你的测试中使用模拟,例如使用你可以做的RhinoMocks:

[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));
}