如何对JSON控制器进行单元测试?

问题描述:

这是我的行动:如何对JSON控制器进行单元测试?

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包含一定的价值。我怎么能在控制器单元测试中做到这一点,而不是通过解析视图结果?

+1

不会解析json响应是最简单的方法吗? – jdeseno

+0

我的印象是单元测试实际上并没有调用视图。是这样吗?如果是,哪种测试是我所寻找的(查看?) –

+1

我相信这个问题已经讨论过[这里](http://stackoverflow.com/questions/336716/how-to-test-json-result-from -rails官能检验)。你在做什么不是单位,而是功能测试。它实际上呈现了这个视图。 –

就像人们上面评论的一样,这将是一个功能测试。

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

如果我使用FactoryGirl有companies_controller在Rspec的:

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上下文,我会尝试传递无效的参数。

+0

不要FactoryGirl需要一个模型,所以在你的例子中,你必须有一个“公司”的模型? – Ninja

+0

你救了我一天的男人。非常感谢。 – Abhinay

使用Rails的内置功能测试:

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 
+0

当你有一个respond_to函数可以返回基于不同块的不同数据时,这个方法就行得通了。在上面的例子中,海报定义了REQUEST发送到控制器的方法,以触发正确的respond_to块。 – FlyingV

我对这种做法略有不同,如果我使用的Jbuilder的宝石,现在可以从Rails的团队。 (这种方法适用于其他可以使JSONXML作为视图的宝石。)我更喜欢在功能测试中尽可能进行单元测试,因为它们可以快得多。使用Jbuilder,您可以将大部分测试转换为单元测试。

是的,你仍然有控制器的功能测试,但有很少的,他们不解析JSON。功能测试仅测试控制器逻辑,而不是渲染的JSON。一个有效的请求可能断言以下(RSpec的)功能测试:

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

我只是验证它是成功的,它呈现模板,并将其传递的项目模板。此时,视图具有所需的信息来进行适当的渲染。

现在测试单元测试Jbuilder视图呈现的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 

而且这个工作在集成测试的形式。

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 

老实说,试图将语法上的细微差别从一种测试类型转变为另一种测试类型是很奇怪的。