我已经搜索了网络,但是,唉,我似乎就是不能让Rspec正确地发送内容类型,这样我就可以测试我的JSON API了。
我的curl输出,它工作正常(应该是一个401,我知道):
mrsnuggles:tmp gaahrdner$ curl -i -H "Accept: application/json" -X POST -d @bleh http://localhost:3000/applications
HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8
Cache-Control: no-cache
X-Ua-Compatible: IE=Edge
X-Runtime: 0.561638
Server: WEBrick/1.3.1 (Ruby/1.9.2/2011-02-18)
Date: Tue, 06 Mar 2012 01:10:51 GMT
Content-Length: 74
Connection: Keep-Alive
Set-Cookie: _session_id=8e8b73b5a6e5c95447aab13dafd59993; path=/; HttpOnly
{"status":"error","message":"You are not authorized to access this page."}
示例来自我的一个测试用例:
describe ApplicationsController do
render_views
disconnect_sunspot
let(:application) { Factory.create(:application) }
subject { application }
context "JSON" do
describe "creating a new application" do
context "when not authorized" do
before do
json = { :application => { :name => "foo", :description => "bar" } }
request.env['CONTENT_TYPE'] = 'application/json'
request.env['RAW_POST_DATA'] = json
post :create
end
it "should not allow creation of an application" do
Application.count.should == 0
end
it "should respond with a 403" do
response.status.should eq(403)
end
it "should have a status and message key in the hash" do
JSON.parse(response.body)["status"] == "error"
JSON.parse(response.body)["message"] =~ /authorized/
end
end
context "authorized" do
end
end
end
end
这些测试从来没有通过,我总是被重定向,我的content-type总是text/html
,不管我在before块中如何指定类型:
# nope
before do
post :create, {}, { :format => :json }
end
# nada
before do
post :create, :format => Mime::JSON
end
# nuh uh
before do
request.env['ACCEPT'] = 'application/json'
post :create, { :foo => :bar }
end
下面是rspec的输出:
Failures:
1) ApplicationsController JSON creating a new application when not authorized should respond with a 403
Failure/Error: response.status.should eq(403)
expected 403
got 302
(compared using ==)
# ./spec/controllers/applications_controller_spec.rb:31:in `block (5 levels) in <top (required)>'
2) ApplicationsController JSON creating a new application when not authorized should have a status and message key in the hash
Failure/Error: JSON.parse(response.body)["status"] == "errors"
JSON::ParserError:
756: unexpected token at '<html><body>You are being <a href="http://test.host/">redirected</a>.</body></html>'
# ./spec/controllers/applications_controller_spec.rb:35:in `block (5 levels) in <top (required)>'
正如您所看到的,我得到了HTML格式的302重定向,即使我试图指定'application/json'。
下面是我的application_controller.rb
,带有rescue_from位:
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, :with => :not_found
protect_from_forgery
helper_method :current_user
helper_method :remove_dns_record
rescue_from CanCan::AccessDenied do |exception|
flash[:alert] = exception.message
respond_to do |format|
h = { :status => "error", :message => exception.message }
format.html { redirect_to root_url }
format.json { render :json => h, :status => :forbidden }
format.xml { render :xml => h, :status => :forbidden }
end
end
private
def not_found(exception)
respond_to do |format|
h = { :status => "error", :message => exception.message }
format.html { render :file => "#{RAILS_ROOT}/public/404.html", :status => :not_found }
format.json { render :json => h, :status => :not_found }
format.xml { render :xml => h, :status => :not_found }
end
end
end
还有applications_controller.rb
,特别是'create'操作,这是我试图测试的。目前它相当难看,因为我使用state_machine
并覆盖了delete方法。
def create
# this needs to be cleaned up and use accepts_attributes_for
@application = Application.new(params[:application])
@environments = params[:application][:environment_ids]
@application.environment_ids<<@environments unless @environments.blank?
if params[:site_bindings] == "new"
@site = Site.new(:name => params[:application][:name])
@environments.each do |e|
@site.siteenvs << Siteenv.new(:environment_id => e)
end
end
if @site
@application.sites << @site
end
if @application.save
if @site
@site.siteenvs.each do |se|
appenv = @application.appenvs.select {|e| e.environment_id == se.environment_id }
se.appenv = appenv.first
se.save
end
end
flash[:success] = "New application created."
respond_with(@application, :location => @application)
else
render 'new'
end
# super stinky :(
@application.change_servers_on_appenvs(params[:servers]) unless params[:servers].blank?
@application.save
end
我已经看过这里的源代码:https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/responder.rb,它似乎应该正确响应,以及一些关于堆栈溢出的问题,似乎有类似的问题和可能的解决方案,但没有一个对我有效。
我做错了什么?
3条答案
按热度按时间r7xajy2e1#
我意识到设置
:format => :json
是一种解决方案(如上所述)。但是,我想测试我的API的客户端将使用的相同条件。我的客户端不会设置:format
参数,而是设置Accept
HTTP头。如果您对这个解决方案感兴趣,下面是我使用的内容:34gzjxbg2#
尝试将
:format
键移动到请求的params散列中,如下所示:让我知道情况如何!这就是我设置测试的方式,它们运行得很好!
k97glaaz3#
这里的答案太晚了!虽然您可以使用
render_views
从控制器中获取json,但您也可以简单地编写一个视图测试:spec/views/posts/show.json.jbuilder_spec.rb