I have a rails project that serves a JSON API with tests written in RSpec. Often when running specs (request specs, specifically), I’m interested in seeing some details about the HTTP request/response...i.e. the request URL, request body, and response body, ideally JSON pretty-formatted for readability. This isn't for the purposes of documentation but rather as part of the development / debugging process.
I have a helper method I wrote which does this...you just drop a method call into your spec and it prints this stuff out.
But, seems like it would be better if there was a switch that’s part of the running specs. RSpec has custom formatters which I thought might be the right direction, but in trying to build one, I can't figure out how to get access to the request/response objects like you can from inside of your spec.
How can I access the request/response objects in my custom RSpec formatter? Or, perhaps another way to approach the problem?
Here's an approach:
Assuming a rails project, in spec_helper.rb, define a global "after" hook like so:
config.after(:each) do #runs after each example
if ENV['PRINTHTTP']
#use request/response objects here, e.g. puts response.status
end
end
Then, you can conditionally enable by adding the environmental variable on the command-line:
$ PRINTHTTP=1 rspec
Related
I'm fairly new to using RSpec, so there's a lot I still don't know. I'm currently working on speccing out a section of functionality which is supposed to run a script when a button is pressed. The script is currently called in a controller, which I don't know if there's a good way to test.
I'm currently using
expect_any_instance_of(ConfigurationsController)
.to receive(:system)
.with('sh bin/resque/kill_resque_workers')
.and_return(true)
in a feature spec and it works, but rubocop is complaining about using expect_any_instance_of and I've been told to only use that method if there was no better way.
Is there any better way to test this? Like is there a way to get the instance of the controller being used, or a better kind of test for this?
A better pattern would be to not inline the system call in your controller in the first place. Instead create a seperate object that knows how to kill your worker processes and call that from your controller. The service object pattern is often used for this. It makes it much easier to stub/spy/mock the dependency and make sure it stops at your application boundry.
It also lets you test the object in isolation. Testing plain old ruby objects is really easy. Testing controllers is not.
module WorkerHandler
def self.kill_all
system 'sh bin/resque/kill_resque_workers'
end
end
# in your test
expect(WorkerHandler).to receive(:kill_all)
If your service object method runs on instances of a class you can use stub_const to stub out the new method so that it returns mocks/spies.
Another more novel solution is dependency injection via Rack middleware. You just write a piece of middleware that injects your object into env. env is the state variable thats passed all the way down the middleware stack to your application. This is how Warden for example works. You can pass env along in your spec when you make the http calls to your controller or use before { session.env('foo.bar', baz) }.
Sorry for my stupid question.
I added the external api to get response in order to check zipcode's validation.
app/validators/zipcode_validator.rb
class ZipcodeValidator < ActiveModel::Validator
def validate(record)
record.errors.add(:zipcode, :blank) if record.zipcode.blank?
record.errors.add(:zipcode, :not_found) if WmsService.wms_delivery_dates(record.zipcode).nil?
end
end
It works fine in real but failed randomly and took more time when I run rspec.
What's the good solution for this situation?
You should not call external APIs in your tests. There are several methods to avoid it:
VCR gem records API response in first call then then replies it from disk (that is fast and reliable).
Mocking HTTP calls, e.g. with WebMock. You need to write specify mocked request and write a response in your specs. It may help you improve test readability also it helps in testing edge cases.
Wrap your service call in your class and replace it with an RSpec stub.
Wrap your service call in your class that accepts adapters. An adapter is responsible for calling external service. In test env pass a test adapter with predetermined responses.
How can I test a .js.rjs response in rails(2.3.8) functional test ?
You can take the simple path and verify the contents being returned seem correct with a functional test.
However, you'll probably get a lot more value from something like Capybara and Celerity that will let you do real integration testing with a live JavaScript engine and verify the RJS causes the page behave you expect.
http://github.com/jnicklas/capybara/blob/master/README.rdoc
There's assert_select_rjs in case you weren't aware of it (like I was). Its something like an assert_tag for RJS output.
I'm using rspec to test a code that may fail depending on the change of a site structure (the external influence I mentioned). I would like to write an example that involves "should raise an error" but I'm not sure if rspec is the right tool to test code in such situations. Could someone point me in some direction?
Thanks in advance
You could write custom matchers
Something like :
site.should_have_valid_structure
Spec::Matchers.define :have_structure
match do |actual|
actual.structure == Site::VALID_STRUCTURE
end
end
Mock the external influence so you can test it properly (if the external influence is a Web page or other HTTP request, WebMock and VCR are great for this). Your tests should not rely on anything external functioning properly -- or improperly. See http://marnen.github.com/webmock-presentation/webmock.html for an overview I wrote last year.
In a Rails application I have a Test::Unit functional test that's failing, but the output on the console isn't telling me much.
How can I view the request, the response, the flash, the session, the variables set, and so on?
Is there something like...
rake test specific_test_file --verbose
You can add puts statements to your test case as suggested, or add calls to Rails.logger.debug() to your application code and watch your log/development.log to trace through what's happening.
In your test you have access to a bunch of resources you can user to debug your test.
p #request
p #response
p #controller
p flash
p cookie
p session
Also, remember that your action should be as simple as possibile and all the specific action execution should be tested by single Unit test.
Functional test should be reserved to the the overall action execution.
What does it mean in practice? If something doesn't work in your action, and your action calls 3 Model methods, you should be able to easily isolate the problem just looking at the unit tests. If one (or more) unit test fails, then you know which method is the guilty.
If all the unit tests pass, then the problem is the action itself but it should be quite easy to debug since you already tested the methods separately.
in the failing test use p #request etc. its ugly, but it can work
An answer to a separate question suggested
rake test TESTOPTS=-v
The slick way is to use pry and pry-nav gems. Be sure to include them in your test gem group. I use them in the development group as well. The great thing about pry and pry nav is you can step through your code with a console, so you can not only see the code as it's executed, but you can also enter console commands during the test.
You just enter binding.pry in the places in the code you want to trigger the console. Then using the 'step' command, you can move line by line through the code as it's executed.