【问题标题】:How to Mock the Internal Method of a class?如何模拟类的内部方法?
【发布时间】:2011-02-15 21:19:35
【问题描述】:

我有一个具有内部方法的类,我想模拟内部方法。但我无法模拟它,即它不是调用模拟函数而是调用原始函数。有没有办法做到这一点?

编辑:实际上我是 Moq 的新手。我有许多类和类的方法要使用 Moq 进行测试。许多类是内部的,许多具有内部方法,许多具有非虚拟方法。并且不能更改方法和类上的签名。谁能告诉我如何使用 Moq 来测试这个场景。或者请向我推荐一些其他易于学习且易于使用的测试框架。

【问题讨论】:

    标签: .net unit-testing moq


    【解决方案1】:

    您可以通过将以下内容添加到您的 AssemblyInfo.cs 来轻松模拟内部虚拟方法:

    [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] // namespace in Moq
    [assembly: InternalsVisibleTo("YourTestClass")]
    

    如果您的程序集是强命名的,您需要包含 DynamicProxyGenAssembly2 的公钥(感谢@bvgheluwe 的评论;来源:Moq quickstart guide

    [assembly:InternalsVisibleTo("DynamicProxyGenAssembly2,PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
    

    我不明白为什么接受的答案说你不应该这样做。当您使用 Roy Osherove 在Chapter 3 of The Art Of Unit Testing 中概述的“提取和覆盖”(本地工厂方法)依赖注入技术时,您不就是这样做的吗?

    【讨论】:

    • 这应该是公认的答案。关于模拟内部方法是否是正确的做法,这完全是另一场争论,但是,如果您已经决定要这样做,那么这就是实现它的方法。
    • internal protected virtual
    • @hvelplund 我说的是你要么需要公钥,要么需要签名。 stackoverflow.com/questions/106880/…
    • @max 你只需要在你自己的程序集被强命名时指定一个公钥。该公钥可以在 github.com/Moq/moq4/wiki/Quickstart 的高级功能下找到,“模拟另一个项目的内部类型,...”
    【解决方案2】:

    将方法标记为internal *protected*(当然也是虚拟的)

    【讨论】:

    • 这行得通,但你能告诉我们为什么行得通吗?
    • @MrLore 之所以有效,是因为“protected internal”意味着该方法可以被 any 程序集中的子类访问,如果你标记它“ virtual" 那么您的模拟子类可以提供自定义实现
    • 此答案优于 Daryn 的答案,因为它不依赖于以后可能会更改的魔术字符串。可以直接在方法签名中添加注释来解释它,而不是隐藏在 assemblyinfo.cs 中。
    • 回应 Moby Disk 的评论:请注意,您仍然需要将内部组件暴露给测试程序集,即 Daryn 的第二个程序集指令仍然有效(否则您将无法设置模拟)。
    【解决方案3】:

    起订量不适用。

    但是您可以使用 MS 提供的免费 Moles 框架来执行此类操作。我在这里写过:Mocking the Unmockable: Using Microsoft Moles with Gallio。 (它不仅适用于 Gallio,而且它给人的总体印象是你可以用 Moles 做什么......)。 另一种选择是 Typemock...

    HTH。 托马斯

    【讨论】:

    【解决方案4】:

    单元测试应该测试一个类的接口。您可以模拟依赖项,但应将类本身的实现细节(例如私有方法)作为整个类的一部分进行测试,而不是单独进行测试,并且不要为测试进行更改(否则您将测试不同的单元然后真的会使用)。

    如果您觉得有必要更改方法以使类可测试,请重构该类,使困难的部分成为依赖项,或者通过参数或子类替代。

    【讨论】:

    • 如果你开发你的代码测试首先,在婴儿步骤?您将经常需要以一种或另一种方式处理内部代码......
    【解决方案5】:

    为什么要模拟内部方法?

    如果你发现需要模拟一个内部方法,比如回避依赖或交互,你也许应该考虑重新设计类。

    Inversion of ControlDependency Injection 是一些可能的设计策略,它们可以减少耦合并增加类的内聚,并消除模拟内部方法的需要。

    我认为 Moq 没有明确的非公开嘲笑途径。

    但是,如果您绝对必须,您可以使用 TypeMock Isolator 来模拟任何东西。

    此外,为了避免在喧嚣中迷失:Thomas 链接了一篇关于使用免费 MS Moles 嘲笑非公共成员的好文章。

    Mocking the Unmockable: Using Microsoft Moles with Gallio

    【讨论】:

    • 我非常不同意:如果你做 TDD,那么嘲笑内部的东西是一件很平常的事……
    • @Thomas - 我理解你的观点。但是您必须意识到,经典策略被定义为测试一个类的行为,通常是通过接口,而不是它的内部实现,因为这将您的测试与内部实现紧密耦合,并在重构时导致惯性和破坏。我不得不说,你的意见是少数。注意:我读过一些你的博客,知道你很周到,TDD 对你很重要——我只是不同意你的不同意见。 ;-)
    • @Poet:同意,如果您采用基于行为的策略,那么仅针对公共接口进行测试当然是有意义的。我的意思是:可以有其他策略,需要测试内部的东西,这不一定是坏事。 - 也许是少数人的事情,但不是错误的。它在它的上下文中也很有意义......我认为没有必要讨论这个......;-)。
    • 如果您想为您的库中其他库不可见的内容编写测试,那么模拟内部方法非常有意义。 “内部”与“私有”相同。
    • 在处理遗留代码时,模拟任何东西和一切都是必不可少的能力。
    【解决方案6】:

    如果您需要测试大量无法更改的代码,最好从一开始就使用 MS Moles 或 TypeMock。

    像 Moq 这样的免费模拟框架无论如何都只支持接口和虚拟方法。听起来你不会走得太远......

    托马斯

    【讨论】:

      猜你喜欢
      • 2015-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多