Rails - Testing JSON API with Functional Tests

How to test JSON result from Ruby on Rails functional tests?

In Rails >= 5

Use ActionDispatch::TestResponse#parsed_body.

Example:

user = @response.parsed_body
assert_equal "Mike", user['name']

In Rails up to 4.x

Use JSON.parse, which takes a string as input and returns a Ruby hash that the JSON represents.

Example:

user = JSON.parse(@response.body)
assert_equal "Mike", user['name']

Rails - Testing JSON API with functional tests

It is easy to do with functional tests. In a user example I would put them in spec/controllers/users_controller_spec.rb in Rspec:

 require 'spec_helper'

describe UsersController do
render_views # if you have RABL views

before do
@user_attributes = { email: "test@example.com", password: "mypass" }
end

describe "POST to create" do

it "should change the number of users" do
lambda do
post :create, user: @user_attributes
end.should change(User, :count).by(1)
end

it "should be successful" do
post :create, user: @user_attributes
response.should be_success
end

it "should set @user" do
post :create, user: @user_attributes
assigns(:user).email.should == @user_attributes[:email]
end

it "should return created user in json" do # depend on what you return in action
post :create, user: @user_attributes
body = JSON.parse(response.body)
body["email"].should == @user_attributes[:email]
end
end

Obviously, you can optimize specs above, but this should get you started. Cheers.

Functional testing of a JSON Rails API

This is a bug, reported by same author of this question. It is not likely to be fixed until Rails 5, or so it seems by looking at the milestone it has been assigned to.

If you land here, like me, after some hours dealing with this issue unknowing that it is really a bug, maybe you want to know that you can do that in an Integration test:

$ rails g integration_test my_integration_test

require 'test_helper'

class MyIntegrationTestTest < ActionDispatch::IntegrationTest
setup do
@owner = Owner.create(name: 'My name')
@json = { name: 'name', value: 'My new name' }.to_json
end

test "update owner passing json" do
patch "/owners/#{@owner.id}",
@json,
{ 'Accept' => Mime::JSON, 'Content-Type' => Mime::JSON.to_s}

assert_response :success
assert_equal 'application/json', response.headers['Content-Type']
assert_not_nil assigns :owner
assert_equal 'My new name', assigns(:owner).name
end
end

How to write test cases for JSON API in rails

You can test your API response for your controller actions, just a reference for your index action.

describe TopicsController do

describe "GET 'index' " do

it "should return a successful response" do
get :index, format: :json
expect(response).to be_success
expect(response.status).to eq(200)
end

it "should return all the topics" do
FactoryGirl.create_list(:topic, 2)
get :index, format: :json
expect(assigns[:topics].size).to eq 2
end

end

end

Functional testing :update action of JSON API in Rails 4

Rubber duck programming really does work. I've got it sorted out:

test "should be able to update location" do

update = { is_private: false }.to_json
patch(:update, update, id: 1)

get :show, id: 1, format: :json
assert_equal json['data'][0]['is_private'], false

end

What is the recommended method of testing a JSON client-server api?

I just started looking at this web functional testing tool called Maxq and I think it has the potential to solve your problem, Maxq acts as a proxy server between your web client and server application.
It sits on top of Junit so that means you could do proper unit testing for your API by asserting the behavior and responses of calls to your server app.
It basically captures and records all the requests you make from a web client and the responses you get back from a server, it also has the ability to generate test scripts of your request which you could use to play back and test on any server.

You should try it out http://maxq.tigris.org/

Testing JSON API in Rails 3.2 using rspec using exact PUT/POST bodies as Backbone would send

I was having the same problem. No matter what I did, or which ways I specified the content type as 'application/json', it just wouldn't work. If there was a suggestion on the internet for setting the content type to json, I tried it. I even tried them all together at the same time.

Ultimately, I traced it to ActionController::ParamsWrapper, where _wrapper_enabled? was always returning false (due to request.content_mime_type being nil). This solution works for me. I was looking for the 'magical' params key to get added as well and this does it.

mime_type = mock
mime_type.stub :ref => :json
request.stub :content_mime_type => mime_type
request.accept = 'application/json'
post :create, widget.as_json

The values are:

widget.as_json #=> {
"created_at"=>nil,
"description"=>"Description 1 - Quidem nihil quae aliquid sed qui.",
"id"=>nil,
"order"=>1,
"title"=>"Title 1 - ut",
"updated_at"=>nil
}

# params hash in the controller.
params #=> {
"created_at"=>nil,
"description"=>"Description 1 - Quidem nihil quae aliquid sed qui.",
"id"=>nil,
"order"=>"1",
"title"=>"Title 1 - ut",
"updated_at"=>nil,
"controller"=>"api/widgets",
"action"=>"create",
"widget"=>{
"title"=>"Title 1 - ut",
"order"=>"1",
"description"=>"Description 1 - Quidem nihil quae aliquid sed qui."
}
}

This is exactly what I wanted. Only title, order, and description are set as attr_accessible, hence the only attributes that appear in the magically created :widget hash.

I am also using active_model_serializers, so the as_json is running through that, in case anyone thinks it matters.

This is part of a public example app I'm building, so this code will be able to be seen in use, if anyone thinks it might be useful.



Related Topics



Leave a reply



Submit