使用rSpec测试Rails API控制器POST

时间:2017-10-20 01:48:36

标签: ruby-on-rails ruby api testing rspec

正如标题所暗示的那样,我只是尝试使用rSpec在API控制器中测试创建操作。控制器看起来像:

lib1/__init__.py

现在,这正是应该做的应该是伟大的。然而,测试......并非如此。这是我对测试部分所拥有的:

module Api
  module V1
    class BathroomController < ApplicationController
      skip_before_action :verify_authenticity_token, only: [:create]`

      def create
        bathroom = Bathroom.new(bathroom_params)
        bathroom.user = current_user
        if bathroom.save
          render json: { status: 'SUCCESS', message: 'Saved new bathroom', bathrooms: bathroom }, status: :ok
        end
      end

      private
      def bathroom_params
        params.require(:bathroom).permit(:establishment, :address, :city, :state, :zip, :gender, :key_needed, :toilet_quantity)
      end

    end
  end
end

我确定这里不止一件事是错的,但我很难找到有关正确测试方法的大量信息。任何见解或建议将不胜感激。

3 个答案:

答案 0 :(得分:2)

我会跳过控制器规格altogther。 Rails 5几乎委托ActionController::TestCase(RSpec包装为控制器规格)到垃圾抽屉。控制器测试不会发送真正的http请求,并将路由器和中间件等Rails的关键部分存根。很快就会发生彻底的贬值和授予单独的宝石。

相反,您想要使用请求规范。

RSpec.describe "API V1 Bathrooms", type: 'request' do
  describe "POST /api/v1/bathrooms" do
    context "with valid parameters" do
      let(:valid_params) do
        {
           bathroom: {
            establishment: "Fake Place",
            address: "123 Main St",
            city: "Cityton",
            state: "NY",
            zip: "11111",
            gender: "Unisex",
            key_needed: false,
            toilet_quantity: 1
          }
        }
      end

      it "creates a new bathroom" do
        expect { post "/api/v1/bathrooms", params: valid_params }.to change(Bathroom, :count).by(+1)
        expect(response).to have_http_status :created
        expect(response.headers['Location']).to eq api_v1_bathroom_url(Bathroom.last)
      end

      it "creates a bathroom with the correct attributes" do
         post "/api/v1/bathrooms", params: valid_params
         expect(Bathroom.last).to have_attributes valid_params[:bathroom]
      end
    end

    context "with invalid parameters" do
       # testing for validation failures is just as important!
       # ...
    end
  end
end

同样发送一堆像render json: { status: 'SUCCESS', message: 'Saved new bathroom', bathrooms: bathroom }, status: :ok这样的垃圾是反模式。

作为回应,您应该发送201 CREATED响应,其中包含一个包含新创建资源的URL或包含新创建资源的响应主体的位置标题。

def create
  bathroom = current_user.bathrooms.new(bathroom_params)
  if bathroom.save
    head :created, location: api_v1_bathroom_url(bathroom)
  else
    head :unprocessable_entity
  end     
end

如果您的客户无法通过查看响应代码来判断响应是否成功,那么您做错了。

答案 1 :(得分:1)

您真的不需要测试数据库中保存的记录中的值,您可以执行以下操作:

expect(post :create, params: params).to change(Bathroom, :count).by(1)

足以测试创建操作在所需的表上创建记录。

然后你可以添加更多规格来测试Bath.new是否接收到预期的参数(这样你就知道保存时会有那些字段),或者存根浴室对象以及它的保存方法来测试响应。

如果你想测试保存的记录是否具有正确的值,我认为规范属于浴室模型而不是控制器(或者更好,是集成测试)。

答案 2 :(得分:0)

所以我遵循了max的建议,但做了一点改动让它运转起来。我的最终代码是:

c:\Python36>pip install os
Collecting os
  Using cached os-0.5.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "c:\python36\lib\tokenize.py", line 452, in open
        buffer = _builtin_open(filename, 'rb')
    FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\swideb\\AppData\\Local\\Temp\\pip-build-_g65v8sr\\os\\setup.py'

    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in C:\Users\swideb\AppData\Local\Temp\pip-build-_g65v8sr\os\

c:\Python36>

关键是使用FactoryGirl创建新用户,因为浴室需要关联的user_id才有效。