我使用NUnit在C#中对私有方法进行单元测试。
例如,我的方法(如果是公共的)应该抛出ArgumentNullException
。我可以断言该方法会抛出ArgumentNullException
,如此:Assert.Throws<ArgumentNullException>(() => method.Call());
但是,由于我使用反射调用私有方法,因此我会为抛出TargetInvocationException
的方法声明ArgumentNullException
,如下所示:Assert.Throws<TargetInvocationException>(() => methodInfo.Invoke(obj, new object[] { params }));
我想为该私有方法声明一个ArgumentNullException
而不是TargetInvocationException
,这样我就可以扫描它的代码,知道它应该做什么而不是调试来查找。
我如何断言实际的异常,而不是TargetInvocationException
?
注意: 这个问题并没有解决单元测试公共与私人方法背后的理论。我和我的团队决定对私有方法进行单元测试,这是否是单元测试的方式与这个问题无关。请参阅this问题上最受欢迎的答案,了解我们的理由。
答案 0 :(得分:6)
找到我的答案:
var exception = Assert.Throws<TargetInvocationException>(() => methodInfo.Invoke(obj, new object[] { params }));
Assert.IsInstanceOf<Exception>(exception.InnerException);
<强>更新强>
Assert.IsNotNull(exception.InnerException)
让我知道存在内部异常。 Assert.IsInstanceOf<Exception>(exception.InnerException);
将断言任何类型的Exception
抛出。我同意两种方式都告诉我们存在内部异常。
然而.....如果我想断言特定类型的内部异常怎么办?
例如,如果我的方法抛出ArgumentNullException
,那么通过执行Assert.IsInstanceOf<FileNotFoundException>(exception.InnerException);
我无法断言使用Assert.IsNotNull
让我知道存在内部异常,但它没有揭示内部异常的类型。因此,这就是我更喜欢在这种情况下使用IsInstanceOf
的原因。
答案 1 :(得分:2)
在Assert上创建一个扩展方法,即带有func的“ThrowsInnerException”,使用Try / Catch包装并抛出InnerException(在您的情况下,对应于ArgumentNullException)
以下是一段代码(未经测试&amp; 无法编译,因为我在没有编辑器的情况下键入它,但它应该会给你一个想法)
public static class AssertExtension
{
public static void ThrowsInnerException<T>(Action action)
{
Assert.Throws<T>(delegate() {
try { action(); }
catch (Exception exc) { throw exc.InnerException; }
});
}
}
答案 2 :(得分:0)
您确定单元测试私有方法是个好主意吗?因为听起来不像。
最好测试调用私有方法的公共方法。
<强>更新强>
更重要的是,尽管我没有看到你的代码,但我认为最好将参数验证放到公共方法并测试它们。
<强> UPDATE2 强>
发现非常相似的SO question
<强> UPDATE3 强>
我在类似案例中使用的方法(用于模拟private
字段)只是将private
方法标记为internal
并添加InternalsVisibleTo(<assembly_with_unit_tests>)
属性被测装配。
这不是一个好主意(实际上我反对这个,当它在团队设计会议上提出时,因为它不对,不纯,等等),但结果却为编写单元测试节省了大量时间。