# Making RSpec Tests More Robust

DevFeed: [Making RSpec Tests More Robust](<https://devfeed.tech/articles/making-rspec-tests-more-robust-21077.md>)

Original publisher: [Read original article](<https://jakeyesbeck.com/2020/07/19/making-rspec-tests-more-robust/>)

Published: 2020-07-19T12:00:00Z

Content type: tutorial

Language: en

Sources: [Jake Yesbeck](<https://devfeed.tech/sources/jake-yesbeck.md>)

Topics: [RSpec](<https://devfeed.tech/topics/rspec.md>), [Ruby](<https://devfeed.tech/topics/ruby.md>), [Testing](<https://devfeed.tech/topics/testing.md>), [Mocking](<https://devfeed.tech/topics/mocking.md>), [API](<https://devfeed.tech/topics/api.md>), [client](<https://devfeed.tech/topics/client.md>), [HTTP](<https://devfeed.tech/topics/http.md>)

Tags: [api](<https://devfeed.tech/tags/api.md>), [code](<https://devfeed.tech/tags/code.md>), [framework](<https://devfeed.tech/tags/framework.md>), [mocking](<https://devfeed.tech/tags/mocking.md>), [ruby](<https://devfeed.tech/tags/ruby.md>), [testing](<https://devfeed.tech/tags/testing.md>), [tests](<https://devfeed.tech/tags/tests.md>)

## AI overview

This article explains how an RSpec test for Ruby API client code can pass even after the tested method is removed. It shows that mocking the method under test may override its implementation and hide a broken contract. The article recommends stubbing the HTTP client response so the test verifies the request behavior without making a real HTTP request.

## Source excerpt

RSpec is a popular framework for testing Ruby code. With an expect assertion, a developer can make sure their code calls the proper method or an acceptable result is returned. The expect().to receive matcher in a test overrides the default implementation and can cause some unintended side effects. To demonstrate this potential problem, assume a very simple API client exists that can update models. Testing an API Client An example api_client.rb class defines a single put method that calls the underlying API with a Faraday connection. # api_client.rb class APIClient def put(url, body) client.put(url, body) end private def client Faraday.new('https://some-cool-api.com') end end Inheriting from api_client.rb is my_model.rb which defines an update method. # my_model.rb class MyModel < APIClient def update(payload) put('/my_models/1', payload) end end A typical test for the update method on MyModel in RSpec might look like: # my_model_spec.rb describe MyModel do describe 'update' do it 'updates the model' do expect(subject).to receive(:put) subject.update({ foo: :bar }) end end end The subject in the above test is MyModel.new and is expected to receive the method put. Since MyModel#update calls the put method, this seems like a reasonable test. $: rspec my_model_spec.rb . Finished in 0.0054 seconds (files took 0.07101 seconds to load) 1 example, 0 failures Running the test produces a passing result, the MyModel class calls its parent method correctly and all is well. Until something changes that the test is unable to detect. Breaking the Contract If MyModel's contract changes, the test should fail. If, for instance, the put method on the APIClient class is removed or commented out, the update method on MyModel would no longer work. # api_client.rb class APIClient # def put(url, body) # client.put(url, body) # end private def client Faraday.new('https://some-cool-api.com') end end However, the test still passes despite this method being removed. $: rspec my_model_spec.rb .