How do you test a module that extends ActiveSupport::Concern?
I have a module that extends ActiveSupport::Concern. Here is the included
block:
included do
after_save :save_tags
has_many :taggings, :as =&g开发者_StackOverflowt; :taggable
has_many :tags, :through => :taggings
end
How can I stub out these calls? I have tried a few ways, but Ruby complains that these methods don't exist when I try and test the module in isolation.
Thanks!
I think you have a couple options, depending on what it is that you want to test.
If you just want to test that the module actually sets up the has_many
associations and after_save
call back, then you could set up a simple rspec expectation:
class Dummy
end
describe Taggable do
it "should setup active record associations when included into models" do
Dummy.should_receive(:has_many).twice
Dummy.should_receive(:after_save).with(:save_tags)
Dummy.send(:include, Taggable) # send is necessary because it's a private method
end
end
You probably can test the save_tags
method pretty easily without further mocking, but if you want to test behavior that depends on the has_many associations being setup you might create another Dummy class with has_many and after_save stubbed out, but with accessors for the associations:
class Dummy
attr_accessor :taggings, :tags
# stub out these two
def self.has_many
end
def self.after_save
end
def initialize
@taggings = []
@tags = []
end
include Taggable
end
describe Taggable do
it "should provide a formatted list of tags, or something" do
d = Dummy.new
d.tags = [double('tag')]
d.formatted_tags.size.should == 1
end
end
We can clean that (somewhat brittle test class) up with a bit of meta programming, though it's up to your judgement on whether this makes the test too difficult to understand.
class Dummy
def self.has_many(plural_object_name, options={})
instance_var_sym = "@#{plural_object_name}".to_sym
# Create the attr_reader, setting the instance var if it doesn't exist already
define_method(plural_object_name) do
instance_variable_get(instance_var_sym) ||
instance_variable_set(instance_var_sym, [])
end
# Create the attr_writer
define_method("#{plural_object_name}=") do |val|
instance_variable_set(instance_var_sym, val)
end
end
include Taskable
end
Before your test starts, you need to make sure you first load the file with the original definition of ActiveSupport::Concern and after that load you have to load your extention. Be sure to load the correct files as the rails autoloading mechanism will find your extention in favor of the original.
精彩评论