[Help] Proper paradigm for RSpec API testing

Skip to first unread message

Byron Katz

Oct 6, 2021, 9:38:20 AMOct 6
to rspec

Hi all,

On a basic negative test case, we want to ensure that when we PATCH to the wrong URL, we get a 404 error. The test looks like this (slightly modified to improve clarity):

    it 'fails if using a bad id' do 
      patch our_endpoint(bad_id), params: form_params, as: :json 
      expect(response).to have_http_status(:not_found) 

when we run this, we get an exception, ActiveRecord::RecordNotFound

It is thrown by #find not finding anything:

    def update 
      post = Post.find(params[:id]) 
      post.update(description: params[:description]) 

My question is: if we're doing RSPec testing, shouldn't the default configuration be to return a 404 HTTP response instead of a Ruby exception? Is my understanding of the paradigm broken? All the examples showing RSpec testing API's work fine - return an HTTP response - for a success (200 response), but if it fails, it throws an exception (and doesn't return an HTTP response)

By the way, I know how to correct this: as a workaround, we change the configuration in config > environments > test.rb as follows:

    # Raise exceptions instead of rendering exception templates.
    config.action_dispatch.show_exceptions = true

or alternately, we can put that setting in the before method of the RSpec file, or in the rails_helper.rb under the spec directory, and again it works fine, but why wouldn't that be already set as default, given the paradigm I'm assuming of how RSpec is meant to work - that is, as much as possible with a outward-facing mentality?



Jon Rowe

Oct 7, 2021, 4:23:49 AMOct 7
to rs...@googlegroups.com
Hi Byron

Its because rspec-rails is a thin wrapper around rails own test helpers, so we do what they do in terms of raising and rendering errors, it would be, in our opinion, more confusing for us to have a different default from Rails.

You received this message because you are subscribed to the Google Groups "rspec" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rspec+un...@googlegroups.com.


Oct 7, 2021, 4:54:50 AMOct 7
to rspec

> By default, in the production environment the application will render either a 404 or a 500 error message. In the development environment all unhandled exceptions are simply raised.

> When running in the production environment, all ActiveRecord::RecordNotFound errors render the 404 error page. Unless you need a custom behavior you don't need to handle this.

To me, it makes sense for you to set `show_exceptions` as you see fit for the test environment, but doing so on `rspec-rails` level might be a surprising for users that have `expect { response }.to raise_error(...)` expectations in their specs.

Jack Royal-Gordon

Oct 7, 2021, 2:13:37 PMOct 7
to rs...@googlegroups.com
Am I wrong in saying that the exception is to be expected in a Controller spec, and that if you want to test the status code you should do so in a Request spec?

When testing controllers, you’re not so much testing what Rails does with the result of the controller as what the controller is doing. And the controller is raising an exception. 

On the other hand, in a request spec, you’d be testing the result of the entire stack, which should be a 404, as Rails rescues ActiveRecord::RecordNotFound and sets the status code to 404.

It seems that the majority of the testing world feels that Controller specs should be deprecated in favor of Request Specs for precisely the reason described above. Do you really care how the controller achieves it’s result, as long as it achieves the correct result?

Personally, I like both types of tests because while the Request spec is an “Acceptance” test, the Controller spec may give you greater insight into what has gone wrong.

Reply all
Reply to author
0 new messages