使用rspec测试ruby超类继承的功能

时间:2016-09-24 00:13:43

标签: ruby rspec

鉴于我有一个抽象类,它为子类提供了继承的功能:

class Superclass
  class_attribute :_configuration_parameter

  def self.configuration_parameter config
    self._configuration_parameter = config
  end

  def results
    unless @queried
      execute
      @queried = true
    end

    @results
  end

  private

  # Execute uses the class instance config
  def execute
    @rows = DataSource.fetch self.class._configuration_parameter
    @results = Results.new @rows, count
    post_process
  end

  def post_process
    @results.each do |row|
      # mutate results
    end
  end
end

这可能由子类使用:

class Subclass < Superclass
  configuration_parameter :foo

  def subclass_method
  end
end

我很难编写RSpec来测试继承和配置的功能而不会滥用全局命名空间:

RSpec.describe Superclass do
  let(:config_parameter) { :bar }

  let(:test_subclass) do
    # this feels like an anti-pattern, but the Class.new block scope
    # doesn't contain config_parameter from the Rspec describe

    $config_parameter = config_parameter

    Class.new(Superclass) do
      configuration_parameter $config_parameter
    end
  end

  let(:test_instance) do
    test_subclass.new
  end

  describe 'config parameter' do
    it 'sets the class attribute' do
      expect(test_subclass._configuration_parameter).to be(config_parameter)
    end
  end

  describe 'execute' do
    it 'fetches the data from the right place' do
      expect(DataSource).to receive(:fetch).with(config_parameter)
      instance.results
    end
  end
end

我在这里嘲笑的真实世界超类还有一些配置参数和其他一些功能,可以很好地测试这种模式。

我是否遗漏了关于课程或考试设计的明显不好的事情?

由于

1 个答案:

答案 0 :(得分:1)

我将跳转到你问题中最具体的部分,关于如何避免使用全局变量将本地参数传递给规范中实例化的虚拟类。

这是您的规范代码:

let(:test_subclass) do
  # this feels like an anti-pattern, but the Class.new block scope
  # doesn't contain config_parameter from the Rspec describe

  $config_parameter = config_parameter

  Class.new(Superclass) do
    configuration_parameter $config_parameter
  end
end

如果您使用Class.new返回的值,则可以使用本地值调用configuration_parameter,并避免使用全局值。使用tap只需对现有代码进行微小更改即可完成此操作:

let(:test_subclass) do
  Class.new(SuperClass).tap do |klass|
    klass.configuration_parameter config_parameter
  end
end

关于如何测试从超类继承的功能的更一般的问题,我认为创建存根子类和为该子类编写规范的一般方法很好。我个人会将您的_configuration_parameter类属性设为私有,而不是测试configuration_parameter方法实际设置的值,而是专注于检查值不同来自超类的值。但我不确定这个问题的范围是什么。