如何对JSON控制器进行unit testing?

这是我的行动:

def my_action str = ... # get json str somehow render :json => str end 

这是我的测试:

 test "my test" do post(:my_action, {'param' => "value"} assert_response :success end 

我想添加另一个断言,即发出的JSON包含一些值。 如何在控制器unit testing中完成,而不是通过解析视图结果?

就像上面评论过的人一样,这将是一次function测试。

最好的方法可能是发出请求,解析JSON响应主体,并将其与预期结果相匹配。

如果我使用FactoryGirl在Rspec中有companies_controller

 describe "GET 'show'" do before(:each) do @company = Factory(:company) get 'show', :format => :json, :id => @company.id end it "should be successful" do response.should be_success end it "should return the correct company when correct id is passed" do body = JSON.parse(response.body) body["id"].should == @company.id end end 

您可以以相同的方式测试其他属性。 此外,我通常有invalid上下文,我会尝试传递无效的参数。

使用Rails的内置function测试:

 require 'test_helper' class ZombiesControllerTest < ActionController::TestCase setup do @request.headers['Accept'] = Mime::JSON @request.headers['Content-Type'] = Mime::JSON.to_s end test "should post my action" do post :my_action, { 'param' => "value" }, :format => "json" assert_response :success body = JSON.parse(response.body) assert_equal "Some returned value", body["str"] end end 

如果我使用现在可从Rails团队获得的Jbuilder gem,我的方法略有不同。 (这种方法适用于将JSON或XML渲染为视图的其他gem。)我尽可能选择function测试的unit testing,因为它们可以更快一些。 使用Jbuilder,您可以将大多数测试转换为unit testing。

是的,你仍然在控制器上进行function测试,但是很少,他们不解析JSON。 function测试仅测试控制器逻辑,而不是渲染的JSON。 对有效请求的function测试可能会声明以下内容(RSpec):

  assert_response :success expect(response).to render_template(:show) expect(assigns(:item).id).to eq(expected_item.id) 

我只是validation它是否成功,它呈现模板,并将项目传递给模板。 此时,视图具有进行正确渲染所需的信息。

现在测试通过unit testingJbuilder视图呈现的JSON。

 describe 'api/v1/items/show.json.jbuilder' do it 'includes foo' do assign(:item, account.build(foo: 'bar')) render json = JSON.parse(rendered) expect(json['item']['foo']).to eq('bar') end # A bunch of other JSON tests... 

使用Minitest和Rails 4.2.4,这个控制器测试对我来说效果很好:

 require 'test_helper' class ThingsControllerTest < ActionController::TestCase test "should successfully create a new thing" do assert_difference 'Thing.count' do @request.headers["Accept"] = "application/json" post(:create, {thing: {name: "My Thing"}}) end assert_response :success json_response = JSON.parse(@response.body) assert_equal json_response["name"], "My Thing" end end 

这是以集成测试的forms工作的。

 require 'test_helper' class ThingsRequestsTest < ActionDispatch::IntegrationTest test "creates new thing" do assert_difference 'Thing.count' do post("/things.json", {thing: { name: "My Thing"}}) end assert_equal 201, status json_response = JSON.parse(@response.body) assert_equal json_response["name"], "My Thing" end end 

老实说,尝试将语法细微差别从一种类型的测试直接保持到另一种测试是很奇怪的。