本文介绍了如何测试控制器帖子:使用 rspec 在 rails 上创建 JSON api?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了通过测试,我一直在扯头发.我有一个如下所示的 JSON API:

{数据": [{"id": "b99f8173-0492-457f-9de9-6c1d8d6832ed","type": "manufacturer_organizations",属性": {"account_number": "随机测试 123"},关系":{组织": {数据": {"id": "fb20ddc9-a3ee-47c3-bdd2-f710541ff89c",类型":组织"}},制造商": {数据": {"id": "1",类型":制造商"}}}},...

我正在尝试在 Rails 中进行 post :create 测试.

let!(:manufacturer_organization) {FactoryGirl.create(:manufacturer_organization)}let(:manufacturer_organization2) { FactoryGirl.create(:manufacturer_organization)}...描述POST 创建"做它发布有效的制造商组织数据"做认证组织 = FactoryGirl.create(:organization)制造商 = FactoryGirl.create(:manufacturer)post :create, Manufacturer_organization2.to_json #我应该在这里放什么?期望(json['data'].length).to eq(2)结尾#=>错误:JSON::ParserError:JSON 文本必须至少包含两个八位字节!

我尝试了各种 SO 帖子(this), this这篇文章

以下是我尝试过的一些尝试:

post :create, params: {organization_id: organization.id,制造商:manufacturer.id, account_number: "123 test account number"}#=>错误:JSON::ParserError:一个 JSON 文本必须至少包含两个八位字节!

post :create, params: :manufacturer_organization_2#=>无方法错误::manufacturer_organization_2:Symbol 的未定义方法`symbolize_keys'

json = { :format =>'json', :manufacturer_organization =>{ :account_number =>"foo123", :organization_id =>组织.id, :manufacturer_id =>制造商.id } }发布:创建,json#=>无方法错误:nil:NilClass 的未定义方法长度"

如何测试我的控制器以通过 post :create 接受 manufacturer_id、organization_id 和 account_number?现在我测试它的方式是计算初始 json['data'].length (initially 1);最后,我希望 json['data'].length 在成功 post :create 后为 2.如何模拟创建有效的制造商组织输入?

对不起,忘记放我的json方法助手了:

def jsonJSON.parse(response.body)结尾

还有,这个通行证:

 描述POST 创建"做它发布有效的制造商组织数据"做认证组织 = FactoryGirl.create(:organization)制造商 = FactoryGirl.create(:manufacturer)帖子:创建,{account_number:测试帐户numba",organization_id:organization.id,manufacturer_id:manufacturer.id}期望(响应).to be_success结尾

同时添加 expect(json['success']).to eq("Yay!") 给我这个错误:

JSON::ParserError:一个 JSON 文本必须至少包含两个八位字节!

控制器:

 def 创建@manufacturer_organization = ManufacturerOrganization.new(manufacturer_organization_params)如果@manufacturer_organization.save把成功!"渲染json:{成功:耶!"}别的puts 对不起,出了点问题!"结尾结尾定义制造商组织参数api_params.permit(:organization_id,:manufacturer_id,:account_number)结尾

while @api_params ||= ActionController::Parameters.new(ActiveModelSerializers::Deserialization.jsonapi_parse(params))

解决方案

在 RSpec 中,您永远*不需要明确格式化参数.

post :create, params: { foo: 'bar' }, 格式: :json

这会将哈希 { foo: 'bar' } 正确格式化为请求正文中的 JSON.

要创建与 JSONAPI.org 结构匹配的哈希,您可以创建一个帮助程序:

# support/api_spec_helper.rb模块 APISpecHelperdef to_json_api(模型){数据: {类型:ActiveModel::Naming.plural(model),属性:model.attributes}.点击做|hash|hash[:id] = model.id 如果 model.persisted?结尾}结尾结尾

您还可以使用 JSONAPI-RB gem 或 ActiveModel::Serializers 来构造/解构 JSONAPI 响应/参数.

需要'rails_helper'需要'api_spec_helper'RSpec.request制造商组织"做包括 APISpecHelper描述POST'/manufacturer_organizations'"做让(:valid_params)做to_json_api(FactoryGirl.build(:manufacturer_organization))结尾让(:invalid_params) 做to_json_api(ManufacturerOrganization.new(foo: 'bad_value'))结尾描述具有有效属性"做它创建了一个制造商组织"做期待做发布'/manufacturer_organizations',参数:valid_params,格式::jsonend.to change(ManufacturerOrganization, :count).by(+1)结尾它有正确的反应"做发布'/manufacturer_organizations',参数:valid_params,格式::json期望(响应).to have_status :created期望(响应.头[:位置]).到eq(制造商组织路径(ManufacturerOrganization.last))结尾结尾描述具有有效属性"做它不会创建制造商组织"期待做发布'/manufacturer_organizations',参数:invalid_params,格式::jsonend.to_not change(ManufacturerOrganization, :count)结尾它有正确的反应"做发布'/manufacturer_organizations',参数:invalid_params,格式::json期望(响应).to have_status :unproccessable_entity结尾结尾结尾结尾

返回正确的状态代码.

返回正确的响应代码非常简单:

def 创建@resource = Resource.create(some_params)如果@resource.save# 你可以通过指向新创建的资源但没有正文来响应头:创建,位置:@resource# 或者渲染 json: @resource,状态::创建,地点:@资源别的渲染 json: { 错误: @resource.errors.full_messages },状态::unprocessable_entity结尾结尾

如果 POST 请求不包含客户端生成的 ID 并且请求的资源已成功创建,服务器必须返回 201 Created 状态代码.
http://jsonapi.org/format/#crud

其他回复
服务器可以使用其他 HTTP 状态代码进行响应.
服务器可以在错误响应中包含错误详细信息.

普遍接受的做法是使用 422 - 无法处理的实体来处理验证错误.

一个小问题是您应该使用 序列化程序 来提供正确的 JSON 响应和还序列化正确的错误对象.

I have been tearing my hair trying to make the test to pass. I have a JSON API that looks like this:

{
  "data": [
    {
      "id": "b99f8173-0492-457f-9de9-6c1d8d6832ed",
      "type": "manufacturer_organizations",
      "attributes": {
        "account_number": "random test 123"
      },
      "relationships": {
        "organization": {
          "data": {
            "id": "fb20ddc9-a3ee-47c3-bdd2-f710541ff89c",
            "type": "organizations"
          }
        },
        "manufacturer": {
          "data": {
            "id": "1",
            "type": "manufacturers"
          }
        }
      }
    },...

I am trying to make a post :create test in rails.

let!(:manufacturer_organization) {FactoryGirl.create(:manufacturer_organization)}
let(:manufacturer_organization2) { FactoryGirl.create(:manufacturer_organization)}

...

  describe "POST create" do
    it "posts a valid manufacturer organization data" do
      authenticate
      organization = FactoryGirl.create(:organization)
      manufacturer = FactoryGirl.create(:manufacturer)

      post :create, manufacturer_organization2.to_json #what should I put here instead?

      expect(json['data'].length).to eq(2)
    end

  #=> error: JSON::ParserError: A JSON text must at least contain two octets!

I have tried various SO posts (this), this, and this article

Here are some of the attempts I have tried:

post :create, params: {organization_id: organization.id, manufacturer: manufacturer.id, account_number: "123 test account number"}
#=> error: JSON::ParserError:
   A JSON text must at least contain two octets!

or

post :create, params: :manufacturer_organization_2
#=>
 NoMethodError:
   undefined method `symbolize_keys' for :manufacturer_organization_2:Symbol

or

json = { :format => 'json', :manufacturer_organization => { :account_number => "foo123", :organization_id => organization.id, :manufacturer_id => manufacturer.id } }
post :create, json
#=>  NoMethodError:
   undefined method `length' for nil:NilClass

How can I test my controller to accept manufacturer_id, organization_id, and account_number via post :create? Right now the way I test it is to count initial json['data'].length (initially 1); at the end I expect json['data'].length to be 2 after successful post :create. How can I mock creating a valid manufacturer_organization input?

Edit:

Sorry, forgot to put my json method helper:

def json
  JSON.parse(response.body)
end

Also, this pass:

  describe "POST create" do
    it "posts a valid manufacturer organization data" do
      authenticate
      organization = FactoryGirl.create(:organization)
      manufacturer = FactoryGirl.create(:manufacturer)
      post :create, {account_number: "Test account numba", organization_id: organization.id, manufacturer_id: manufacturer.id}
      expect(response).to be_success
    end

while adding expect(json['success']).to eq("Yay!") gives me this error:

JSON::ParserError: A JSON text must at least contain two octets!

Controller:

  def create
    @manufacturer_organization = ManufacturerOrganization.new(manufacturer_organization_params)
    if @manufacturer_organization.save
      puts "success!"
      render json: {success: "Yay!"}
    else
      puts "Sorry, something went wrong!"
    end
  end


def manufacturer_organization_params
    api_params.permit(:organization_id, :manufacturer_id, :account_number)
end

while @api_params ||= ActionController::Parameters.new(ActiveModelSerializers::Deserialization.jsonapi_parse(params))

解决方案

In RSpec you never* need to explicitly format the params.

post :create, params: { foo: 'bar' }, format: :json

This will properly format the hash { foo: 'bar' } as JSON in the request body.

To create a hash which matches the JSONAPI.org structure you can create a helper:

# support/api_spec_helper.rb
module APISpecHelper
  def to_json_api(model)
    {
      data: {
        type: ActiveModel::Naming.plural(model),
        attributes: model.attributes
      }.tap do |hash|
        hash[:id] = model.id if model.persisted?
      end
    }
  end
end

You can also use the JSONAPI-RB gem or ActiveModel::Serializers to constuct/deconstruct JSONAPI responses/params.


require 'rails_helper'
require 'api_spec_helper'

RSpec.request "Manufacturer organizations" do

  include APISpecHelper

  describe "POST '/manufacturer_organizations'" do
    let(:valid_params) do
      to_json_api(FactoryGirl.build(:manufacturer_organization))
    end
    let(:invalid_params) do
      to_json_api(ManufacturerOrganization.new(
        foo: 'bad_value'
      ))
    end

    describe "with valid attributes" do
      it "creates a manufacturer organization" do
        expect do
          post '/manufacturer_organizations', params: valid_params, format: :json
        end.to change(ManufacturerOrganization, :count).by(+1)
      end

      it "has the correct response" do
        post '/manufacturer_organizations', params: valid_params, format: :json
        expect(response).to have_status :created
        expect(response.headers[:location]).to eq(
          manufacturer_organization_path(ManufacturerOrganization.last)
        )
      end
    end

    describe "with valid attributes" do
      it "does not create a manufacturer organization" do
        expect do
          post '/manufacturer_organizations', params: invalid_params, format: :json
        end.to_not change(ManufacturerOrganization, :count)
      end

      it "has the correct response" do
        post '/manufacturer_organizations', params: invalid_params, format: :json
        expect(response).to have_status :unproccessable_entity
      end
    end
  end
end

Returning the correct status codes.

Returning the correct response codes is pretty simple:

def create
  @resource = Resource.create(some_params)
  if @resource.save
    # you can respond by pointing at the newly created resource but with no body
    head :created, location: @resource
    # or
    render json: @resource,
           status: :created,
           location: @resource
  else
    render json: { errors: @resource.errors.full_messages },
           status: :unprocessable_entity
  end
end

The commonly accepted practice is to use 422 - Unprocessable Entity for validation errors.

One small concern is that you should use a serializer to give the correct JSON response and also serialize the correct error objects.

这篇关于如何测试控制器帖子:使用 rspec 在 rails 上创建 JSON api?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 23:26