On 14 Aug 2010, at 11:34, Mike Howson wrote: > Just wondered what people thoughts are to testing module's to be > included in mixin's? Seems to me there are two main approaches:-
Hi Mike I've been doing a lot of this sort of coding lately, as I've been extracting duplicated code into a mini-framework based on modules. > 1. Test the behavior in a mixin object that includes the module because > its the behavior of the object thats important not the code structure. > > 2. Test the module in isolation as it potentially code be included > anywhere. I'm not sure I know how option 2 is even possible, unless your module is all module methods, as you can't call instance methods on a module directly. However, it's easy to do this in RSpec with some Ruby meta-magic: module MyModule def foo "bar" end end describe MyModule do let(:class_with_my_module) { Class.new do include MyModule end } subject { class_with_my_module.new } its(:foo) { should eq bar } end > If the best approach is 2 - to test the module in isolation and the > module uses instance variables or methods from the object its being > mixed with then we would need to create a test object in the rspec test > that included the module and defined the required instance variables and > methods. Does this lead to 1 being the best approach as we are not then > forced to mock up a mixin just to test the module? I'm not 100% sure but I *think* the snippet above is an implementation of what you describe here. Please correct me if I misunderstood. > The question came about because I recently had to get an untested rails > module under test that was included in a number of controllers and > depended on 'request' and 'response'. I was then faced with either > testing one of the controllers that included that module but also added > further complexity or defining a new thin controller used solely for > testing the module within the spec file. In this case, you may be able to get some mileage with the above code, but using `Class.new(ActionController::Base)`. You can test individual objects that include your module with shared examples, for example: module Fooable def foo "bar" end end class Baz include Fooable # Oops - this is overriding Fooable#foo def foo "quux" end end shared_examples_for "a Fooable object" do # Optional before(:each) do unless respond_to?(:fooable) raise "You must provide instance method fooable" end end it "should have a foo of 'bar'" do fooable.foo.should eq "bar" end end describe Baz do subject { Baz.new } it_should_behave_like "a Fooable object" do let(:fooable) { subject } end end My recommendation at the moment is to make the shared examples work fully-integrated (ie, no mocks). I've run into issue where shared examples rely on mocks, which I haven't solved yet (at least not in my code - it's my next TODO). Currently I'm doing both the above. The isolated module spec proves the module enchants objects with the correct behaviour, the shared examples double-check that you haven't broken that behaviour in concrete classes. See also the recent thread "Evaluating shared example customisation block before shared block" from 30th July onwards (it goes on to talk about passing parameters to shared example groups, which is possible in RSpec-2 master). HTH Ash -- http://www.patchspace.co.uk/ http://www.linkedin.com/in/ashleymoran _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users