Stubbing Controller Actions in Rspec Request Specs

Stubbing controller actions in RSpec request specs

I ended up stubbing the controller method using any_instance.

it "Should return 500 upon server error" do
UsersController.any_instance.stub(:index).and_raise(ArgumentError)
get "/users.json"
response.code.should eq("500")
response.body.should have_json_path("error")
end

Note:

Stubbing controller methods in a request spec doesn't make sense. But... In this case I am using the request spec suite as the acceptance criteria. One of the requirement was to ensure, all the error codes and messages match the API design.I was able to induce the server to raise all the HTTP error codes specified in the API design. Only edge case was the internal server error(i.e. 500). I had no means of inducing the controller to raise this error. Since, I am testing error reply and since this reply is independent of the location and source of the exception I decided to stub it.

RSpec: Stub controller method in request spec

You're supposed to be on vacation.

I think the right way is to avoid stubbing as much as you can in a request spec, doorkeeper needs a token to authorize so I'd do something like:

describe 'Items', type: :request do
describe 'GET /items' do
let(:application) { FactoryBot.create :oauth_application }
let(:user) { FactoryBot.create :user }
let(:token) { FactoryBot.create :access_token, application: application, resource_owner_id: user.id }
before do
get '/items', access_token: token.token
@parsed_body = JSON.parse(response.body)
end

it 'includes all of the items' do
expect(@parsed_body).to include(item_1)
expect(@parsed_body).to include(item_2)
end
end
end

Here are some examples of what those factories might look like.

Lastly, nice SO points!

Rspec: stub out controller action

You won't be able to stub a controller action from within a request spec. However you can stub the AJAX request, so that the controller action is never reached. Webmock is a good choice.

Correct way of stubbing method call in RSpec request

The point is that authenticate_user assigns user to the variable (and you use it later). Please try:

allow(DecodeAuthenticationCommand).to receive_message_chain(:call, :result).and_return(user)

With the test double, you will have to define all methods for the user, such as contracts. Also, you are checking if the contract was created - in my opinion, it is perfectly fine to use a real object for the user.

Stubbing authentication in request spec

A request spec is a thin wrapper around ActionDispatch::IntegrationTest, which doesn't work like controller specs (which wrap ActionController::TestCase). Even though there is a session method available, I don't think it is supported (i.e. it's probably there because a module that gets included for other utilities also includes that method).

I'd recommend logging in by posting to whatever action you use to authenticate users. If you make the password 'password' (for example) for all the User factories, then you can do something like this:


def login(user)
post login_path, :login => user.login, :password => 'password'
end

RSpec stubbing only works for first request, does not work for subsequent requests

Finally discovered the problem.

In test.rb, config.cache_classes was set to false (no idea why since it defaults to true).

You want config.cache_classes to be set to true in testing environments, otherwise classes will be reloaded on every request and its methods will override the stub.

Rspec: stubbing controller methods ineffective (before_filter, private)

The solution is to use a method other than visit in the spec. Apparently, visit is intended for feature specs only. Instead, use get or post etc.

Controller Specs vs Request Specs?

Rails 3 & 4

Controller specs - A controller spec is an RSpec wrapper for a Rails functional test. It allows you to simulate a single http request in each example, and then
specify expected outcomes

Request specs - Request specs provide a thin wrapper around Rails' integration tests, and are
designed to drive behavior through the full stack, including routing
(provided by Rails) and without stubbing (that's up to you).

So if you want to test API controllers I would recommend to use Controller specs as you are testing single requests.


Rails 5+

Rails 5 improved the speed and realism of request specs over Rails version 4's controller and request specs. The official recommendation of the Rails team and the RSpec core team is to write request specs instead (of controller specs).



Related Topics



Leave a reply



Submit