【问题标题】:How to RSpec a shared ActiveRecord module without associated database table?如何在没有关联数据库表的情况下 RSpec 共享 ActiveRecord 模块?
【发布时间】:2011-10-05 23:25:54
【问题描述】:

使用 RSpec 2.6 / Rails 3.1 / Postgres:

我正在编写任何 AR 模型都可以包含的支持模块(在我的 lib/ 中)。我想为这个模块写规范。它需要包含在 AR::Base 模型中,因为它在包含时会加载关联并依赖于一些 AR 方法,但我不想在为此模块编写 rspec 时使用我现有的模型。

我只想创建一个任意的 AR 模型,但显然它在数据库中没有关联的表,并且 AR 正在消亡。这是我想做的事情:

class SomeRandomModel < ActiveRecord::Base
  include MyModule

  # simulate DB attributes that MyModule would be using
  attr_accessor :foo, :bar, :baz 
end

describe SomeRandomModel do
  it '#some_method_in_my_module' do
    srm = SomeRandomModel.new(:foo => 1)
    srm.some_method_in_my_module.should eq(something)
  end
end

当然,我在 postgres 中收到一些关于不存在关系的错误。

感谢您的帮助!

【问题讨论】:

    标签: ruby-on-rails activerecord rspec


    【解决方案1】:

    还有另一种方法可以使用 rpsecs shared_examples_for 来解决这个问题,我在代码 sn-p 中提到了一些技巧,但有关更多信息,请参阅 relishapp-rspec-guide

    有了这个,您可以在任何包含它的类中测试您的模块。 所以您确实在测试您在应用程序中使用的内容。

    我们来看一个例子:

    # Lets assume a Movable module
    module Movable
      def self.movable_class?
        true
      end
    
      def has_feets?
        true
      end
    end
    
    # Include Movable into Person and Animal
    class Person < ActiveRecord::Base
      include Movable
    end
    
    class Animal < ActiveRecord::Base
      include Movable
    end
    

    现在让我们为我们的模块创建规范:movable_spec.rb

    shared_examples_for Movable do
      context 'with an instance' do
        before(:each) do
          # described_class points on the class, if you need an instance of it: 
          @obj = described_class.new
    
          # or you can use a parameter see below Animal test
          @obj = obj if obj.present?
        end
    
        it 'should have feets' do
          @obj.has_feets?.should be_true
        end
      end
    
      context 'class methods' do
        it 'should be a movable class' do
          described_class.movable_class?.should be_true
        end
      end
    end
    
    # Now list every model in your app to test them properly
    
    describe Person do
      it_behaves_like Movable
    end
    
    describe Animal do
      it_behaves_like Movable do
        let(:obj) { Animal.new({ :name => 'capybara' }) }
      end
    end
    

    【讨论】:

    • 这个答案应该被接受。这是处理模块规范的正确方法。
    【解决方案2】:

    我面临着类似的问题,经过多次谷歌搜索后,我决定在我的 RSpec 测试中设置和拆除表格。这是我一直在使用的sn-p:

    describe "stuff you are testing do" do
    
      before :all do
        m = ActiveRecord::Migration.new
        m.verbose = false  
        m.create_table :random_class do |t| 
          t.string :field_1
          t.integer :field_2
        end
      end
    
      after :all do
        m = ActiveRecord::Migration.new
        m.verbose = false
        m.drop_table :random_class
      end
    
      class RandomClass < ActiveRecord::Base
        attr_accessible :field_1, :field_2
      end
    
      # Your regular RSpec before(:each) blocks and tests
      # ...
    
      # e.g.
      it "should be able to use RandomClass" do
        rc = RandomClass.create! :field_1 => "hello", :field_2 => 5
        rc.field_1.should == "hello"
        rc.field_2.should == 5
      end
    
    end
    

    我不喜欢这个解决方案,但它确实有效。希望这对某人有帮助!要么就是这样,要么激励他们发布实现这一目标的最佳方式。

    :)

    【讨论】:

    • 是的,我放弃并使用现有的模型大声笑。不过这个也不错!让我看看有没有其他回应。否则,这是一个很好的答案!谢谢!
    • 这可能有效,但这不是一个好的解决方案。您不必使用 rspecs shared_examples 或 stackoverflow.com/questions/16453266/… 来查看burninggrammas 答案以获得更好的解决方案
    • 我在强调这一点-我很佩服您取得了一些进展,但这是一个公认的答案,比最好的,更简单,更稳定的答案要多得多(正如其他人指出的那样-burninggramma的shared_examples_for)
    • 我同意@burninggrammas 的回答更好,而且我已经这样做了一段时间了:)
    【解决方案3】:

    你可以覆盖self.columns

    class Tableless < ActiveRecord::Base
      def self.columns
        @columns ||= [];
      end
    end
    

    然后你可以创建一个新的实例 reguralry

    let(:dummy_instance) { Tableless.new }
    it { is_expected.to be_valid}
    

    【讨论】:

    • 在 Rails 5.0 中,使用 def self.load_schema!; @columns_hash = {}; end
    【解决方案4】:

    goggin13,谢谢你的回答。它主要对我有用,除了我必须将迁移实例方法更改为类方法。即:

    来自

     m = ActiveRecord::Migration.new
     m.verbose = false  
     m.create_table ...
    

     m = ActiveRecord::Migration
     m.verbose = false  
     m.create_table ...
    

    【讨论】:

    • 共享的答案是最好的(但未被接受)的答案,用户不应与更复杂和不太稳定的答案混淆。
    【解决方案5】:

    这是 goggin13 的答案的一个细微变化,它修复了迁移(如 Zac 所述)并修复了表名:

    describe "stuff you are testing do" do
    
      before :all do
        m = ActiveRecord::Migration
        m.verbose = false  
        m.create_table :random_classes do |t| 
          t.string :field_1
          t.integer :field_2
        end
      end
    
      after :all do
        m = ActiveRecord::Migration
        m.verbose = false
        m.drop_table :random_classes
      end
    
      class RandomClass < ActiveRecord::Base
        attr_accessible :field_1, :field_2
      end
    
      # Your regular RSpec before(:each) blocks and tests
      # ...
    
      # e.g.
      it "should be able to use RandomClass" do
        rc = RandomClass.create! :field_1 => "hello", :field_2 => 5
        rc.field_1.should == "hello"
        rc.field_2.should == 5
      end
    
    end
    

    【讨论】:

    • 当正确答案是 shared_examples_for 时,它增加了对 goggin13 答案的支持。
    猜你喜欢
    • 1970-01-01
    • 2017-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多