0

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

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'sshared_example_for并编写一次测试,然后使用 rspec's 在必要的模型中运行测试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 函数的值,无论是通过类的实例还是通过类本身,而不是查看已经在类实例上定义的方法?

4

2 回答 2

1

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

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
于 2016-03-11T21:57:34.437 回答
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

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

于 2016-03-11T21:36:28.303 回答