如何测试模块中的私有函数

时间:2011-04-17 21:53:06

标签: ruby unit-testing ruby-1.9.2

我有两个问题:

第1部分

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

我在this stackoverflow帖子上读到了约定:

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方法来调用方法从我的测试?

有什么想法吗?

3 个答案:

答案 0 :(得分:5)

关于测试私有方法存在一些争议,您将在其他答案中看到。在测试它们之前,您应该考虑它是否是最佳选择。 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将公开且可见。

结束修改

另见:

答案 1 :(得分:2)

我想说你有三种选择。

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

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

  3. 将这些函数公开并测试它们。这在技术上最简单,但不如选项2清洁。

答案 2 :(得分:1)

有两种情况:

  1. 私有方法由公共方法调用,或者由公共方法调用的私有方法调用,或者由公共方法调用的私有方法调用的私有方法调用,或者...(您得到这个想法)。在这种情况下,您不需要测试私有方法,因为它已经通过公共方法进行了测试。
  2. 私有方法永远不会被公共方法调用。在这种情况下,你也不需要测试它,你可以简单地删除它,因为它永远不会被调用。
  3. 因此,在这两种情况下,您根本不需要首先测试它。

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

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

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

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