C#:在密封类中模拟和测试受保护(或私有)方法——方法

Posted

技术标签:

【中文标题】C#:在密封类中模拟和测试受保护(或私有)方法——方法【英文标题】:C#: Mocking and testing protected (or private) methods in sealed classes -- approaches 【发布时间】:2011-06-12 12:13:45 【问题描述】:

我有一个带有受保护方法的密封类,我想测试其行为。这使得很难直接测试,也很难模拟。

它位于不是以 TDD 方式开发的代码库中,我现在正在为特定功能添加单元测试。

在这种情况下,可能的一般方法是什么?目前我有:

    解封类。 然后在我们的测试代码中创建一个派生自该类的代理或适配器,以隧道访问受保护的方法。 将受保护方法中的行为分解为委托/函子,然后重新注入。 然后独立地测试被分解的行为。 通过调用继承层次结构中使用受保护方法的最接近的公共方法进行测试。 当被测代码以外的代码发生变化时,可能会导致大量嘲笑,并暴露在风险之中——创建脆弱的测试。 使用反射来访问受保护的方法。 那就直接调用吧。

还有吗?

【问题讨论】:

【参考方案1】:

密封类中的protected 方法实际上与private 相同(我想如果你密封一个派生类,其中基类有一个protected 成员,这些自然会出现。)

而且测试private 方法毫无意义。因为除了可以通过定义类的public 方法访问之外,它们没有public 行为,因此应通过测试public 方法来测试它们的行为。

【讨论】:

有时为了测试公共方法,模拟私有方法很方便。我认为,这是主要用例 @anthares:这听起来有点误导。如果private 方法是public 方法实现的一部分,则不应对其进行模拟。 好吧,给你举个例子:我花了半天时间才接近模拟出我需要的一切,只是使用反射直接调用某个受保护的方法。如果我必须从最近的公共方法中模拟出所有内容,我可能必须将任务传递给我的孩子以完成。这并不是说我一般不同意你的看法——只是对于一些代码库还有其他实际限制。 (和 +1) @Tim Barrass:我想我在说你。我的观点是,您不需要在密封类上模拟受保护的方法。它与私有方法相同,私有方法不应在测试公共方法的隐式测试之外进行测试。任何时候你花半天时间做某事,或者担心你的孩子会继承这项工作,你应该退后一步,问问它是否值得。成本/收益是这里的关键。 不,我认为我们从不同方面提出了相同的观点;您对成本/收益的看法完全正确。【参考方案2】:

Microsoft Moles 有助于使用非虚拟方法模拟未密封的类。它不能模拟私有方法,但这是多余的,因为您可以模拟在特定类之外使用的更高级别的公共方法,并且您可以模拟所有必要的行为来模拟一个公共方法。

为什么要测试私有/受保护的方法?您可以使用内部方法和InternalVisibleToAttribute 来实现这一点。但一般来说,您应该只测试公共行为(即只测试公共接口)。

【讨论】:

感谢 Moles 指针,非常有趣。我对 Jason 做了一个关于嘲笑公共方法的快速回复。【参考方案3】:

假设您有能力使更改相当容易,我通常会选择第二种选择。鉴于如果您无法通过其公共接口测试受保护的 /private 方法正在做什么,那么它可能无论如何都不符合单一职责原则,并且代码可能会被分成两个类并使用组合来代替。

【讨论】:

【参考方案4】:

您可以使用一些框架进行模拟 - 例如JustMock(由 Telerik 提供)支持密封私有方法的模拟......不幸的是,我认为 JustMock 的这一部分是付费的,但至少您可以尝试试用版.

【讨论】:

方便,ta;我目前正在使用 Rhino Mocks。【参考方案5】:

您可以使用 JustMock 框架。 例如:

double value = 0;
var fakeFilterSetHelper = Mock.Create<FilterSetHelper>(Behavior.CallOriginal);
Mock.NonPublic.Arrange<double>(fakeFilterSetHelper, memberName: "GetPriceRangeFromSession").Returns(value);

【讨论】:

以上是关于C#:在密封类中模拟和测试受保护(或私有)方法——方法的主要内容,如果未能解决你的问题,请参考以下文章

受保护和私有有啥区别? [复制]

是否可以为具有 1)返回类型 void、2)访问说明符私有或受保护的方法编写单元测试?

打字稿:使父类中的公共方法成为派生类中的私有/受保护方法

是否可以模拟受保护的属性和方法

编写高质量代码改善C#程序的157个建议——建议49:在Dispose模式中应提取一个受保护的虚方法

使用受保护和继承时无法访问在类中声明的私有成员