2011-10-05 6 views
13

Uso de RSpec 2.6/Rails 3.1/Postgres:Cómo RSpec un módulo ActiveRecord compartido sin tabla de base de datos asociada?

Estoy escribiendo un módulo de soporte (en mi lib /) que puede incluir cualquier modelo de AR. Me gustaría escribir especificaciones para este módulo. Necesita ser incluido por un modelo AR :: Base, porque carga asociaciones cuando se incluye y se basa en algunos métodos AR, pero no quiero usar mi modelo existente al escribir rspec para este módulo.

Me gustaría crear un modelo AR arbitrario, pero obviamente no tendría una tabla asociada en la base de datos y AR está muriendo. Aquí es Kindda lo que quiero hacer:

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 

Por supuesto, me sale un error en postgres sobre la relación no existente.

Gracias por su ayuda!

Respuesta

14

Hay una forma alternativa de resolver este problema usando rpsecs shared_examples_for, menciono algunos trucos en el fragmento de código, pero para obtener más información, vea esto relishapp-rspec-guide.

Con esto puede probar su módulo en cualquiera de las clases que lo incluyen. Así que realmente está probando lo que usa en su aplicación.

Veamos un ejemplo:

# 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 

Ahora vamos a crear especificaciones para nuestro módulo: 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 
+4

Esta respuesta debe ser la aceptada. Es la forma correcta de manejar las especificaciones del módulo. –

15

Me enfrento a un problema similar, y después de mucho buscar en Google me he conformado con configurar y derribar tablas en mis pruebas de RSpec. He aquí el fragmento He estado usando:

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 

No estoy enamorado de esta solución, pero funciona. Espero que sea útil para alguien! O eso o los inspira a publicar la mejor manera de lograr esto.

:)

+0

Sí, dejé y utilicé el modelo existente lol.¡Pero esto también es bastante bueno! Déjame ver si hay otras respuestas. De lo contrario, esta es una buena respuesta! ¡Gracias! – janechii

+2

Esto podría funcionar, pero no es una buena solución. No deberías tener que mirar la respuesta de burngrammas para una mejor solución usando rspecs shared_examples o también http://stackoverflow.com/questions/16453266/rails-rspec-testing-concerns-class-methods –

+0

Estoy dinging this a point - Admiro que tienes algo en marcha, pero esta es una respuesta aceptada con más puntos que la mejor, más simple y más estable respuesta (como señalaron otros - burninggramma's shared_examples_for) –

0

goggin13, gracias por su respuesta. Principalmente funcionó para mí, excepto que tuve que cambiar los métodos de la instancia de migración a los de clase. es decir:

De

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

Para

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

La respuesta compartida es la mejor (pero no aceptada) respuesta por un largo camino y los usuarios no deben confundirse con la respuesta más complicada y menos estable. –

0

Aquí hay una ligera variación en la respuesta de goggin13 que fija las migraciones (como se ha señalado Zac) y fija el nombre de la tabla:

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 
+0

Dinging it a point, ya que agrega soporte a la respuesta de goggin13 cuando se comparte la respuesta correcta_examples_for –

2

Puede puede sobrescribir la self.columns

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

continuación, puede crear un nuevo instancia de reguralry

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

En Rails 5.0, use 'def self.load_schema !; @columns_hash = {}; fin – depquid

Cuestiones relacionadas