15

Using RSpec 2.6 / Rails 3.1 / Postgres:

I am writing a supporting module (in my lib/) that any AR model can include. I'd like to write spec for this module. It needs to be included by an AR::Base model, because it loads associations when included and relies on some AR methods, but i don't want to use my existing model when writing rspec for this module.

I would just like to create an arbitrary AR model, but obviously it would not have a table associated in the database and AR is dying. Here's kindda what I want to do:

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

Of course, i get some error in postgres about the relation not existing.

Thanks for your help!

5 Answers 5

16

There is an alternative way to solve this problem using rpsecs shared_examples_for, I mention few tricks in the code snippet but for more info see this relishapp-rspec-guide.

With this you can test your module in any of the classes which include it. So you really are testing what you use in your application.

Let's see an example:

# 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

Now lets create spec for our module: 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
Sign up to request clarification or add additional context in comments.

1 Comment

This answer should be the one accepted. It's the proper way to handle module's spec.
15

I am facing a similar problem, and after much googling I have settled on just setting up and tearing down tables in my RSpec tests. Here's the snippet I've been using:

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

I'm not enamored of this solution, but it works. Hope that's helpful for someone! Either that or inspires them to post the best way to accomplish this.

:)

4 Comments

Yea, i gave up and used existing model lol. But this is pretty good too! Let me see if there's any other responses. Otherwise, this is a good answer! Thanks!
This might work, but it is not a good solution. You should not have to Look at burninggrammas answer for a better solution using rspecs shared_examples or also stackoverflow.com/questions/16453266/…
I'm dinging this a point - I admire that you got something going but this is an accepted answer with more points than the best, simpler and more stable, answer (as pointed out by others - burninggramma's shared_examples_for)
I agree that @burninggrammas's answer is better and i've been doing that without realizing it for some time :)
2

You can overwite self.columns

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

then you can create a new instance reguralry

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

1 Comment

In Rails 5.0, use def self.load_schema!; @columns_hash = {}; end
0

goggin13, thanks for your answer. It mostly worked for me except that I had to change the migration instance methods to class ones. i.e.:

From

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

To

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

1 Comment

The shared answer is the best (but unaccepted) answer by a long way and users shouldn't be confused with the more complicated and less stable answer.
0

Here's a slight variation on goggin13's answer which fixes the migrations (as Zac noted) and fixes the table name:

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

1 Comment

Dinging it a point as it adds support to goggin13's answer when the correct answer is shared_examples_for

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.