Grape is not a controller or view. An example of how to write an rspec test would be great.
This is what I have working as a request spec in spec/requests/api_v1.rb. There's got to be a better way :)
require 'spec_helper'
describe Api_v1 do
describe "GET /api/v1/widgets/:slug" do
it "returns a widget represented by slug" do
@widget = Fabricate(:widget)
get "/api/v1/widgets/" + @widget.slug
response.body.should == MultiJson.encode(@widget.serializable_hash)
end
end
end
looks pretty similar to what I've got
Has anyone written spec tests for Grape helpers?
@johnyman: i tried to do it but couldn't figure out anything nice - instead I made helpers thin wrappers calling another module (eg. api_cache_helper calls api_cache) and wrote tests for the module.
I added a section in https://github.com/intridea/grape/pull/56 about how to write a test with rspec. I'm going to close this.
Daniel, any idea how to ensure that a helper method was called from an endpoint? I'm testing my helpers in a similar way you're describing, but I have a hard time testing that get('/api/v1/foo') actually calls helper method bar. Without this, I have a hard time doing good integration testing without repeating myself.
@johnyman: did you try stubbing the module method or using the regular rspec stuff that counts calls? afterall this is just a module
The problem is which module ends up getting stubbed? I've tried doing everything from MyApi.should_receive(:bar) to Object.any_instance.should_receive(:bar) to no avail. If you set a breakpoint in the test and run
Object.descendants.select{|o| o.instance_methods.include?(:bar)}
What you'll get are all dynamic classes. This makes setting up the expectation pretty tricky.
Ok. So I don't know the answer to this. The helpers get mounted and you can no longer stub them.
I think testing the fact that a helper is called is the same as stubbing in testing a controller. It's something I personally dislike in suggested rails testing practices. The important part of an API is to avoid regressions, ie. behave the same externally. So if the helper does something meaningful, it should have an impact either on the result or on the system. For example, I have an authenticated helper - so I make sure my APIs return 401 unless the user is logged in. I also have a logger helper, so I make sure it logged an entry to the database on every call. Etc. What does knowing that the helper is called actually test?
I have more than one route which calls the same helper which does a nontrivial amount of work. The simplest example that is close to what I'm doing is: you have two routes both return {:status => some_helper} as part of the response payload, and that some_helper can return one of 5 status messages based on different conditions. My goal is to make sure that neither one of these routes regress. I also want to avoid duplicating tests for these two routes by adding the 5 tests to the helper and then ensuring that the routes call the helper. This also seems suboptimal, it's somewhat of a "house of cards" test suite, I agree with you there.
How would you go about testing something like that? This logic doesn't belong in the model; it's specific to a version of the API.
I'd copy paste the crap out of tests :)
You can generate tests too if it feels like you're repeating yourself, if your input is X and your expected result is a 403 error and if given "Z" it's 200:
{ "X" => 403, "Z" => 200 }.each_pair { |input, output|
it "given #{input} should produce #{output}" do
get "/api/v1/method/name?q=#{input}"
response.status.should == output
end
}
Replace the status code with the invocation of the helper. And if you need to eval in the context of the test, replace by a string and call instance_eval(output).
For a longer discussion, we can take it offline dblock[at]dblock[dot]org - I am very interested in this since I am giving a talk on Grape at NYC.rb next week.
seriously? testing helper methods in a ruby library doesn't seem CRITICAL to you? In what universe does this ever make sense?!
This is a HUGE flaw in this library, and you just find it fit to simply close the issue and say "hey, I don't like testing stuff, so this ain't getting fixed", this is Ruby, we do everything TDD, and you just think it's logical just to ignore that?
Fixing this shouldn't be horribly hard, instead of doing that god awful complicated crap you're doing, simply apply the methods on something which can be easily accessed and thus, stubbed. The API class should have a helper method which points to the helper module. It's as simple as that.
just to elaborate, I have a helper method called current_user, I want to simulate a situation where the user is logged in, thus, current_user isn't nil.
I just have absolutely no way of doing someting.stub(:current_user).and_return(user) to do that. This makes testing the logged in scenario impossible. And thus, writing using this otherwise nice library, impossible, because I won't write untested code...
@unorthodoxgeek First, I opened the issue 2 years ago and the issue title was "How do I write a spec test for an API method provided by Grape?" An example was added to README and I closed the issue.
There was a discussion on helpers. You do make a very good point, so you should feel free to open a new issue that says exactly what you're saying.
@dblock sorry dude, will do.
@unorthodoxgeek no worries ;)
Can someone assist me with this? http://stackoverflow.com/questions/16799944/sending-data-in-post-request-application-xml-in-integration-test
All the examples are for simple get requests
Most helpful comment
seriously? testing helper methods in a ruby library doesn't seem CRITICAL to you? In what universe does this ever make sense?!
This is a HUGE flaw in this library, and you just find it fit to simply close the issue and say "hey, I don't like testing stuff, so this ain't getting fixed", this is Ruby, we do everything TDD, and you just think it's logical just to ignore that?
Fixing this shouldn't be horribly hard, instead of doing that god awful complicated crap you're doing, simply apply the methods on something which can be easily accessed and thus, stubbed. The API class should have a helper method which points to the helper module. It's as simple as that.