On Tue, Feb 2, 2010 at 19:00, Frank Lakatos <m...@franklakatos.com> wrote:
> Hi guys, been following for about 3 weeks, first question - This might help a little: http://bit.ly/ONpXE To bring things back to Rails, I use mock_model whenever I want to design controller behavior without relying on the underlying model behavior. I tend to start using mock_model and mostly stubbing model behavior, then as controller behavior begins to reveal itself as model behavior, I push that into the model and mock those methods more frequently. I find this rule of thumb helpful: stub unless you're certain to want to verify this time that the client invoke the server correctly, and never, never mock multiple methods at once. If you want to mock multiple methods, you probably have too complex an interaction. > app/controller/projects_controller#create > > def create > �...@client = > current_user.company.clients.find(params[:project][:client_id]) > �...@project = @client.projects.build(params[:project]) > if @client.save > flash[:notice] = "Added: #...@project.name}" > else > render :new > end > end > > spec/controller/projects_controller_spec > > describe ProjectsController do > describe "POST 'create'" do > > before do > �...@current_user = mock_model(User) > controller.stub(:current_user).and_return @current_user > �...@company = mock_model(Company) > �...@current_user.should_receive(:company).and_return @company > �...@clients = mock("Client List") > �...@company.should_receive(:clients).and_return @clients > end > > describe "when client is found" do > > before do > �...@client = mock_model(Client) > �...@clients.should_receive(:find).and_return @client > end > > describe "on successful save" do > > before do > �...@projects = mock_model(ActiveRecord) > �...@client.should_receive(:projects).and_return @projects > �...@project = mock_model(Project) > �...@projects.should_receive(:build).and_return @project > �...@client.should_receive(:save).and_return true > �...@project.should_receive(:name).and_return "New Project" > end > > it "should set up the flash" do > post "create", {:project => {:client_id => 1}} > flash[:notice].should_not be_nil > end > > end > > end > > end > > > end > > > Let me know how it sounds, and it looks like I'm doing so far Not bad, but I'd probably extract a method for current_user.company.clients.find(params[:project][:client_id]) and possibly for @client.projects.build(params[:project]) in order to reduce the number of details that have to go into a single spec. def find_client_for_current_user(client_id) current_user.company.clients.find(client_id) end def build_new_project(client, project_attributes) client.projects.build(project_attributes) end def create @client = find_client_for_current_user(params[:project][:client_id]) @project = build_new_project(@client, params[:project]) if @client.save flash[:notice] = "Added: #...@project.name}" else render :new end end Now I can write these specs: stub each of the methods in the first three columns... find_client | build_project | save || expected_result valid | valid | true || added project nil | valid | shouldn't happen || exception (?) valid | fails | shouldn't happen || exception (?) valid | valid | false || errors; render new and finally: 1. stub :find_client to answer mock_model(Client); controller should receive :build_new_project with the mock model 2. stub :find_client to answer nil; controller should not receive :build_new_project 3. stub :find_client to answer mock_model(Client); mock model should receive :save That's the initial spec list I'd write. -- J. B. (Joe) Rainsberger :: http://www.jbrains.ca :: http://blog.thecodewhisperer.com Diaspar Software Services :: http://www.diasparsoftware.com Author, JUnit Recipes 2005 Gordon Pask Award for contribution to Agile practice :: Agile 2010: Learn. Practice. Explore. _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users