【问题标题】:Asserting Exceptions for Private Methods断言私有方法的异常
【发布时间】:2012-05-23 03:29:53
【问题描述】:

我正在使用 NUnit 对 C# 中的私有方法进行单元测试。

例如,我的方法(如果公开)预计会抛出 ArgumentNullException。我可以断言该方法会像这样抛出ArgumentNullExceptionAssert.Throws<ArgumentNullException>(() => method.Call());

但是,由于我使用反射调用私有方法,因此我会为抛出 ArgumentNullException 的方法断言 TargetInvocationException,如下所示:Assert.Throws<TargetInvocationException>(() => methodInfo.Invoke(obj, new object[] { params }));

我想为该私有方法声明一个ArgumentNullException 而不是TargetInvocationException,这样我就可以扫描它的代码并知道它期望做什么,而不是通过调试来找出答案。

我将如何断言实际异常,而不是 TargetInvocationException

注意: 这个问题没有解决单元测试公共与私有方法背后的理论。我和我的团队已经决定对私有方法进行单元测试,这是否是单元测试的方式与这个问题无关。请参阅this 问题上最受好评的答案以了解我们的基本原理。

【问题讨论】:

  • 这是否是一个好主意是一回事,但您能检查一下InnerException 属性吗?
  • 感谢@GeorgeDuckett 引导我朝着正确的方向前进。

标签: c# exception nunit assert private-methods


【解决方案1】:

找到我的答案:

var exception = Assert.Throws<TargetInvocationException>(() => methodInfo.Invoke(obj, new object[] { params }));
Assert.IsInstanceOf<Exception>(exception.InnerException);

更新

Assert.IsNotNull(exception.InnerException) 让我知道存在内部异常。 Assert.IsInstanceOf&lt;Exception&gt;(exception.InnerException); 将断言任何类型的 Exception 抛出。我同意这两种方式都告诉我们存在内部异常。

但是.....如果我想断言特定类型的内部异常怎么办?

例如,如果我的方法抛出一个ArgumentNullException,那么我不能通过Assert.IsInstanceOf&lt;FileNotFoundException&gt;(exception.InnerException); 来断言使用Assert.IsNotNull 让我知道存在内部异常,但它不会显示内部异常的类型.因此,这就是我在这种情况下更喜欢使用IsInstanceOf 的原因。

【讨论】:

  • 仅供参考——这与检查 InnerException 不为空是一样的,因为任何异常都是如此。
【解决方案2】:

您确定对私有方法进行单元测试是个好主意吗?因为听起来好像不是。

最好测试调用私有方法的公共方法。

更新

还有,虽然我没有看到你的代码,但是我觉得还是把参数验证放到公共方法里面去测试比较好。

更新2
发现很相似SO question

Update3
我在类似情况下使用的方法(用于模拟 private 字段)只是将 private 方法标记为 internal 和将InternalsVisibleTo(&lt;assembly_with_unit_tests&gt;) 属性添加到被测程序集。
这不是一个好主意(实际上,当它在一次设计会议上在团队中提出时我反对这个,因为它不正确,不纯粹等),但结果它为编写单元测试节省了很多时间。

【讨论】:

  • 调用这些私有方法的公有方法已经过测试。如上所述,我的团队决定测试私有方法,因为公共方法中有很多部分。
  • this。最受欢迎的答案解释了我们采取这条路线的理由。
  • 测试公共方法必然意味着您已经测试了私有方法。它们没有区别。
【解决方案3】:

在 Assert 上创建一个扩展方法,即采用 func 的“ThrowsInnerException”,用 Try/Catch 包装并抛出 InnerException(在您的情况下,对应于 ArgumentNullException)

这是一段代码(未经测试 & 无法编译,因为我在没有编辑器的情况下输入了它,但它应该可以让你知道)

public static class AssertExtension 
    {
        public static void ThrowsInnerException<T>(Action action) 
        {
            Assert.Throws<T>(delegate() {
                try { action(); }
                catch (Exception exc) { throw exc.InnerException; }
            });
        }
    }

【讨论】:

  • 感谢您抽出宝贵时间回答所提问题。
猜你喜欢
  • 2018-06-07
  • 2019-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-10
  • 1970-01-01
相关资源
最近更新 更多