For me, this has certainly been the most enjoyable and interesting part of using RSpec - finding answers to these questions in a context that suits the project. Of course, i am new to this, but have found an approach that works well for my current project. However, my approach is wide open to review and improvement and will no doubt evolve well beyond its current scope in future.
I am still reading and re-reading Dan's previous mail regarding the Builder pattern as it is very elegant, although i am not using now as i feel that it could introduce a little too much overhead to maintain the Builders. I am also considering Dan's mantra and with more RSpec experience i'll gain a better insight into how this can work in rails. Here's what i'm doing that works well for our project: Mocking * In views and controllers I always use mocks and stub out any responses that i spot or are flagged up by autotest (yep, autotest is ace for highlighting those methods that need stubbing) * In models, i only use real models for the model specific to the test. I always mock all other interacting models - so in a test for a project with many tasks, the tasks model is mocked and then stubbed. * I only define the expectation for any mock or real model in one place. So, in our app, the expected definition of a Project is defined once and that definition is used by all tests that use that object, from views to models. It's default values can be overwritten, but the expectation is set for all uses. More info below: Factories So far, I am finding that a factory class is offering a useful *glue* between the intentionally separated unit tests. So, even though all tests are isolated from each other with mocks, they still share an expectation of what any used mock should look like. This enables me to be aware of the system wide impact of a change to a small component of the system. I fully accept that this should be covered by integration testing and not unit testing, but on a quick project, i am not sure i can justify (not yet at least) the time to write unit tests and then integration tests, especially as the test team will go at the app with Scellenium. As i say, mine is an evolving platform :-) Here's how we are using a factory. I hope it helps and that i don't get too grilled for the design and implementation :-) ### # The factory class houses the expected # definition of each object and returns # mocks or real models depending on the request # It's attribute values (but not keys) can be overwritten # See 'validate_attributes' method below ### module Factory def self.create_project(attributes = {}, mock = false) @default_attributes = { :name => "Mock Project", :synopsis => "Mock Project Synopsis" } create_object(attributes,mock,Project) end private def self.create_object(custom_attributes,mock,object_type) validate_attributes(custom_attributes) attributes = @default_attributes.merge(custom_attributes) if mock attributes.each_pair do |key, value| mock.stub!(key).and_return(value) end mock else mock = object_type.create attributes end end ### # The following method validates that any received # custom attribute's key is in the expected attribute # list for the object. If not, the test fails, forcing # the developer to keep the factory defaults up to # date with any changes ### def self.validate_attributes(attributes) attributes.each_key {|a| raise "Unrecognised attribute '#{a}' was passed into the Factory" if [EMAIL PROTECTED](a)} true end end ### # Projects controller test interacts # with the Factory and receives mocks ### describe ProjectsController do include Factory before(:each) do @project1 = Factory.create_project({}, mock_model(Project)), @project2 = Factory.create_project({:name => "My second project", :synopsis => "This is another fantastic project"}, mock_model(Project)) @projects = [EMAIL PROTECTED],@project2] end end ### # The Project model test interacts with # the Factory and receives real models ### describe Project do include Factory before(:each) do Project.destroy_all #Real project @project = Factory.create_project #Stub Role @role = Factory.create_role({},mock_model(Role)) @role.stub!(:quoted_id).and_return(true) @role.stub!(:[]=).and_return(true) @role.stub!(:save).and_return(true) end end _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users