简体   繁体   中英

Using mock's and stubs over rails and rspec API

My question is more of general nature. While working on different kinds of code, I have run onto rspec tests for controllers where some code use rails and rspec API, and other use mock's and stubbing,and I have came to thinking.

I am thinking of what are pons and cons of using mock's and stubs over built in rails and rspec API for testing controllers and if someone can explain which approach is better ?

In general they can do the same (at least to some point). Other then difference between how the code will look like, or making a tests more expressive,

If your question is about why to mock and stub, then there is no short answer. Those tasks make testing much easier, since it allows you to better control the behaviour of your software during test. In that way, tests gets faster, simpler and more "unitary".

For example, in a create action in your controller, you may want to test the behaviour of it when the model is saved or not. If you're not stubbing, you would need to create two different instances; one that is valid and another that is not.

it "redirects to message with a notice on successful save" do
  message_params = FactoryGirl.attributes_for(:message)
  post :create, message_params
  flash[:notice].should_not be_nil
  response.should redirect_to(Message.last)
end
it "renders a :new template with a notice on unsuccessful save" do
  message_params = FactoryGirl.attributes_for(:message, name: nil)
  post :create, message_params
  flash[:notice].should_not be_nil
  response.should render_template :new
end

As you can see, it was necessary to create two instances of Message ; one valid and one invalid. It was necessary that we used FactoryGirl to create them. In other words, the test isn't completely unitary, since other things could go wrong on the creation of the instances. What we really wanna test is: does it redirects to page X if saving was successful? So we just want to make sure that @message.valid? returns true in one case and false in the other case. This can easily be done using stub:

it "should redirect to message with a notice on successful save" do
  Message.any_instance.stubs(:valid?).returns(true)
  post 'create'
  flash[:notice].should_not be_nil
  response.should redirect_to(Batch.last)
end
it "should render new template with a notice on unsuccessful save" do
  Message.any_instance.stubs(:valid?).returns(false)
  post 'create'
  flash[:notice].should be_nil
  response.should render_template('new')
end    

So, in that case, the tests are so much lighter, since we didn't have to create instances of the objects, we just stub the method to return what we want it to return. There are many other reasons to use it, and you can learn more reading about mocking and stubbing.

However, if your question is, to use built-in mocking and stubbing features of Rspec, or to use external gems, such as Mocha, then the answer is shorter: Today, I believe its more about personal preference. In the past, frameworks like Mocha had features that Rspec didn't have, such as the any_instance method used above. But Rspec evolved, and today it's as good as the others.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM