3

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

例如,我的方法(如果是公开的)预计会抛出一个ArgumentNullException. 我可以断言该方法会抛出ArgumentNullException这样的问题:Assert.Throws<ArgumentNullException>(() => method.Call());

但是,由于我正在使用反射调用私有方法,因此我会TargetInvocationException为抛出ArgumentNullException类似这样的方法声明一个:Assert.Throws<TargetInvocationException>(() => methodInfo.Invoke(obj, new object[] { params }));

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

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

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

4

3 回答 3

7

找到我的答案:

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);Using来断言它Assert.IsNotNull让我知道存在内部异常,但它不会显示内部异常的类型。因此,这就是为什么我更喜欢IsInstanceOf在这种情况下使用。

于 2012-05-15T15:59:44.160 回答
2

在 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; }
            });
        }
    }
于 2012-05-15T15:31:12.970 回答
0

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

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

更新

更重要的是,尽管我没有看到你的代码,但我认为最好将参数验证放在公共方法中并对其进行测试。

Update2
发现非常相似的SO 问题


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

于 2012-05-15T15:19:35.550 回答