动态生成ActiveSupport :: Concern的测试

时间:2016-03-11 20:49:14

标签: ruby-on-rails ruby rspec activesupport-concern

我有一个像这样定义的关注:

module Shared::Injectable 
  extend ActiveSupport::Concern

  module ClassMethods
    def injectable_attributes(attributes)
      attributes.each do |atr|
        define_method "injected_#{atr}" do
           ...
        end
      end
    end
  end

以及使用此类问题的各种模型:

Class MyThing < ActiveRecord::Base
  include Shared::Injectable
  ...
  injectable_attributes [:attr1, :attr2, :attr3, ...]
  ...
end

这可以按预期工作,并生成一组我可以在类的实例上调用的新方法:

my_thing_instance.injected_attr1
my_thing_instance.injected_attr2
my_thing_instance.injected_attr3

当我试图测试这个问题时,我的问题出现了。我想避免为使用该问题的每个模型手动创建测试,因为生成的函数都做同样的事情。相反,我认为我可以使用rspec&#39; s shared_example_for并编写测试一次,然后使用rspec&#39; it_should_behave_like在必要的模型中运行测试。这很好用,但是我在访问我传递给injectable_attributes函数的参数时遇到了问题。

目前,我在共享规范中这样做:

shared_examples_for "injectable" do |item|
  ...
  describe "some tests" do
    attrs = item.methods.select{|m| m.to_s.include?("injected") and m.to_s.include?("published")}
    attrs.each do |a|
      it "should do something with #{a}" do
        ...
      end
    end
  end
end

这很有效,但显然这是一种可怕的方式。是否有一种简单的方法可以通过类的实例或通过类本身访问传入injectable_attributes函数的值,而不是查看已在类实例上定义的方法?

2 个答案:

答案 0 :(得分:1)

既然你说你想避免为每个使用关注点的模型手动创建测试,因为生成的函数都做同样的事情&#34;,那么单独测试模块的规范怎么样? ?

module Shared
  module Injectable
    extend ActiveSupport::Concern

    module ClassMethods
      def injectable_attributes(attributes)
        attributes.each do |atr|
          define_method "injected_#{atr}" do
            # method content
          end
        end
      end
    end
  end
end

RSpec.describe Shared::Injectable do
  let(:injectable) do
    Class.new do
      include Shared::Injectable

      injectable_attributes [:foo, :bar]
    end.new
  end

  it 'creates an injected_* method for each injectable attribute' do
    expect(injectable).to respond_to(:injected_foo)
    expect(injectable).to respond_to(:injected_bar)
  end
end

然后,作为一个选项,如果你想编写一般规范来测试一个对象是否真的具有可注入属性而不重复你在模块规范中得到的东西,你可以添加如下内容您的MyThing规范文件:

RSpec.describe MyThing do
  let(:my_thing) { MyThing.new }

  it 'has injectable attributes' do
    expect(my_thing).to be_kind_of(Shared::Injectable)
  end
end

答案 1 :(得分:0)

尝试这样的事情怎么样:

class MyModel < ActiveRecord::Base
  MODEL_ATTRIBUTES = [:attr1, :attr2, :attr3, ...]
end

it_behaves_like "injectable" do 
  let(:model_attributes) { MyModel::MODEL_ATTRIBUTES }
end

shared_examples "injectable" do
  it "should validate all model attributes" do 
    model_attributes.each do |attr|
      expect(subject.send("injected_#{attr}".to_sym)).to eq (SOMETHING IT SHOULD EQUAL)
    end
  end
end

它不会为每个属性创建单独的测试用例,但它们都应该为每个属性都有一个断言。这至少可以为你提供一些工作。