Как избежать переоценки поведения частного метода? - PullRequest
2 голосов
/ 17 апреля 2019

Учитывая, что:

  • Тестирование частных методов не является хорошей практикой.
  • Интерфейс со многими открытыми методами также не является хорошей практикой.

Предположим, у меня есть следующий код:

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, не переусердствовав их? Я не хотел бы повторять его логику при тестировании классов X и Y.

Я не думаю, что делать методы RedisHelper публичными - это хорошо, потому что они будут публичными и в X и Y.

Ответы [ 2 ]

2 голосов
/ 19 апреля 2019

Прямой ответ

Проверьте модуль напрямую:

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_for есть в обоихX и Y - они должны сами обрабатывать пространство имен при каждом вызове redis.Кроме того, оба key_for & prefix можно вызывать в любом из этих классов (подклассы и и любых других включенных модулей), даже если они оба являются внутренними для "пространства имен 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
0 голосов
/ 19 апреля 2019

В RSpec вы можете использовать общие примеры :

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 это, вероятно, решается простым включением модуля с общими тестами.

...