【问题标题】:Unit test behaviour after exception is thrown?抛出异常后的单元测试行为?
【发布时间】:2011-03-17 13:33:10
【问题描述】:

我刚开始进行单元测试,有一个场景我不知道如何解决,而且我的解决方案感觉不对。

我有一些代码可以做某事,如果它失败,即抛出异常,异常将被捕获并记录如下。

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

我想测试如果抛出错误,它会调用 LogError() 方法,该方法又会调用另一个对象。

我已经使用模拟记录器来解决这个问题,并捕获第一个抛出的异常,然后断言调用了 LogError 方法。但是,这感觉不需要捕获异常?我记得读过一些东西,在测试中尝试捕获是不好的?有没有其他方法来执行这个测试或者我应该重构逻辑?任何想法都会很棒!

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

编辑

使用 Mark Rushakoff 答案,测试变得像魅力一样发挥作用。

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

【问题讨论】:

  • 通过在每行前面添加四个空格来格式化代码块。 StackOverflow 的 Markdown 语法将其显示为 &lt;pre&gt; 标签。

标签: unit-testing exception-handling tdd nunit rhino-mocks


【解决方案1】:

您没有说明您使用的是哪个版本的 NUnit,但首选方法是 Assert.Throws 方法。

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

@Bruno's answer 适用于您的测试框架不提供检查抛出异常的工具。

【讨论】:

【解决方案2】:

单元测试实际上可以在满足异常条件时检查是否抛出异常。例如:

方法:

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

测试:

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!
   } 

}

【讨论】:

  • 我只是在输入几乎相同的内容。好答案!
【解决方案3】:

如果你使用 NUnit 作为你的 ut 测试框架,你可以使用 ExpectedException 属性来检查方法是否真的抛出了预期的异常。这种方法不需要您在测试代码中使用 try 和 catch 块。

您可以查看以下示例以获取更多详细信息 ExpectedException example

【讨论】:

  • 现在几乎不推荐使用 ExpectedException。 Assert.Throws 更可取,因为它不易出错。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-21
  • 1970-01-01
  • 1970-01-01
  • 2013-01-20
相关资源
最近更新 更多