【问题标题】:How to test private functions in a module如何测试模块中的私有函数
【发布时间】:2011-08-07 11:46:59
【问题描述】:

我有一个两部分的问题:

第 1 部分

我有一个模块,它有一个公共类方法,它依赖于模块中的一些私有帮助方法。测试这些私有辅助方法的最佳方法是什么?它们包含需要测试的复杂逻辑,但不应公开调用它们,因为它们本身并没有提供任何有用的东西。

我在thisstackoverflow 帖子上读到了惯例:

module GTranslate
  class Translator
    def perform( text ); 'hola munda'; end
  end

  def self.translate( text )
    t = Translator.new
    t.perform( text )
  end
end

然后在GTranslate::Translator 类的公共方法上编写测试。但是,我不希望此类能够实例化或调用它们的方法。

第 2 部分

看到模块上的公共方法定义为self.someMethodName,这是否意味着辅助方法必须定义为self.helperName

不会有模块的实例(如果你甚至可以创建模块的实例(我是 Ruby 新手)),所以我不能使用在实例上定义的 send 方法从我的测试?

有什么想法吗?

【问题讨论】:

    标签: ruby unit-testing ruby-1.9.2


    【解决方案1】:

    正如您将在其他答案中看到的那样,关于测试私有方法存在一些争论。在测试它们之前,您应该考虑它是否是最佳选择。 David Brady 有一个很棒的podcall with Robert C. (Uncle Bob) Martin,他们在其中讨论了这个问题以及一些可能的解决方案,包括通过公共接口进行测试,以及重构为一个单独的类。

    话虽如此,这是Ruby。如果您想测试私有方法,请使用instance_eval(或class_eval 用于类方法)在模块的上下文中运行您的测试。

    编辑:在一些快速的 IRB 工作模块之后需要更多的工作

    给定:

    module Foo
      class << self
        private
        def bar
          ...
        end
      end
    end
    

    测试 Foo.bar 放入你的测试文件:

    Module Foo
      class << self
        puiblic :bar
      end
    end
    

    在您的测试期间,bar 将是公开可见的。

    结束编辑

    另见:

    【讨论】:

      【解决方案2】:

      我会说你有三个选择。

      1. 找到一种使用类的公共方法测试功能的方法。所有类的功能通常都应该通过它的公共方法公开。如果您不能仅使用其公共方法来测试一个类,这可能表明设计存在更深层次的问题。

      2. 如果选项 1 不起作用(有时确实不起作用),请将私有功能重构为一个单独的类,其中这些方法是公共的。这似乎是您的建议,我认为这没有问题。测试是您正在构建的系统的一个组成部分,应该这样对待。在我看来,将功能公开“仅用于测试”是完全有效的。

      3. 公开函数并对其进行测试。这在技术上是最简单的,但不如选项 2 干净。

      【讨论】:

      • 只有第一个选项有意义。
      【解决方案3】:

      有两种情况:

      1. 私有方法被公共方法调用,或者被公共方法调用的私有方法,或者被公共方法调用的私有方法调用的私有方法,或者……(你明白了)。在这种情况下,您不需要测试私有方法,因为它已经通过公共方法进行了测试。
      2. 私有方法永远不会被公共方法调用。在这种情况下,你也不需要测试它,你可以简单地删除它,因为它永远不会被调用。

      因此,在这两种情况下,您根本不需要首先对其进行测试。

      (请注意,它比这要复杂一些,因为私有方法可能通过反射或其他方式调用。但要点是:某个地方的某个人调用私有方法,在这种情况下,它会通过那个人进行测试,或者没有人调用私有方法,在这种情况下它是死代码。)

      如果我可以为测试驱动开发做一个小广告:在TDD中,未经测试的私有方法实际上是不可能存在的。将私有方法引入系统的唯一方法是从已经测试过的公共方法中提取。 (实际上,在 TDD 中,任何未经测试的代码是不可能存在的,因此未经测试的私有方法不可能存在的说法是微不足道的。)

      一般来说,私有方法通常是通过从已经变得太大或太复杂的公共方法中提取它们来创建的。这样做的好处是提取方法重构有一个非常方便的属性:与所有其他重构一样,它不会改变外部可观察的行为,但许多其他重构不同,这需要相当大的变化对于内部逻辑(例如空对象重构或用多态性重构替换条件),它不会改变内部逻辑。它只是随机播放代码。 (事实上​​,使用像 Rubinius、IronRuby 或 JRuby 这样的优秀优化编译器,对私有方法的调用可能会被内联,因此实际执行的代码在提取方法之前和之后都是 100% 相同的.)

      因此,如果您的代码在您移入私有方法之前已经过测试,那么在您移入私有方法后它保证仍会被测试。

      【讨论】:

      • 1 和 2 都不成立的两种情况。 a)“深度防御”错误处理,如果您的公共接口正确,您将永远无法访问错误处理代码,但您需要防御猴子补丁等。 b) 练习者代码路径所需的输入相当于运行代码本身。加密例程属于这一类。
      猜你喜欢
      • 1970-01-01
      • 2016-07-02
      • 1970-01-01
      • 2014-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多