如何避免过度测试私有方法的行为?

时间:2019-04-17 15:50:47

标签: ruby unit-testing private-methods

鉴于此:

  • 测试私有方法不是一个好习惯。
  • 具有许多公共方法的接口也不是一种好习惯。

假设我有以下代码:

module RedisHelper
  private

  def key_for(id)
    [prefix, id].join('-')
  end

  def prefix
    self.class.name.split('::').last.underscore
  end
end
class X
  include RedisHelper

  def perform(id)
    key = key_for(id)
    redis.sadd(key, [:bar])
  end
end
class Y
  include RedisHelper

  def perform(id)
    key = key_for(id)
    redis.set(key, :foo)
  end
end

在不过度测试key_for / prefix方法的情况下,最好的方法是什么?在测试类XY时,我不想重复其逻辑。

我不认为公开RedisHelper的方法是件好事,因为它们在XY中也是公开的。

2 个答案:

答案 0 :(得分:2)

直接回答

直接测试模块:

def test_redis_key_namespacing
  dummy_class = Class.new do # this anonymous class will not pollute namespace
    include RedisHelper

    public :key_for

    def self.name
      'Dummy'
    end
  end

  assert_equal 'Dummy-hello', dummy_class.new.key_for('hello')
end

总体建议

我建议不要使用RedisHelper模块。尝试将“ Redis命名空间代码”逻辑保持在一起并与其他代码分开是很好的,但实际上,到处都是“ Redis命名空间代码”。

key_forXY中-他们必须处理每次调用redis的命名空间。同样,key_forprefix都可以在任何这些类(子类任何其他包含的模块)中调用,即使它们是都在“ Redis名称空间”内部。

在您的应用程序中,“ Redis键命名空间”似乎是一个重要概念。它可以在多个地方被不同的无关区域重用。使其成为“事物”:

class NsRedis
  key_methods = Redis.instance_methods(false).select do |m|
    Redis.instance_method(m).parameters.first == [:req, :key]
  end

  # some metaprogramming, but it's static, much better than method_missing!
  key_methods.each do |m_name|
    define_method(m_name) do |key, *args|
      Redis.current.public_send("#{@namespace}:#{key}", *args)
    end
  end

  def initialize(namespace)
    @namespace = namespace
  end
end

# Now, anywhere you're going to need it, including tests:
class X
  def initialize
    @redis = NsRedis.new(self.class.name)
  end

  def do_something
    @redis.set(:my_key, 'my_val') # "unaware" of the namespacing at usage
  end
end

答案 1 :(得分:0)

在RSpec中,您可以使用shared examples

RSpec.shared_examples "Redis namespacing helper" do
  # your tests for key_for, prefix and what-have-you
end

RSpec.describe X do
  it_behaves_like "Redis namespacing helper"
end

RSpec.describe Y do
  it_behaves_like "Redis namespacing helper"
end

在minitest中,这可能是通过在共享测试中简单地包含模块来解决的。