我已经在这个问题上困了好几天了,请帮帮忙!
我的问题是:我试图在Rails中的posts控制器中进行Rspec测试,但当我进行更新时,发生了这个错误,我不知道为什么
#posts_controller.rb
class PostsController < ApplicationController
before_action :set_post, only: %i[show update destroy]
before_action :authenticate_user!, except: %i[index show]
def index
posts = Posts::List.new(params).execute
render json: posts, meta: pagination(posts), each_serializer: PostSerializer, status: :ok
end
def show
authorize @post
render json: @post, serializer: PostSerializer, list_comments: true, status: :ok
end
def create
@post = authorize Posts::Create.new(post_params, current_user).execute
render json: @post, serializer: PostSerializer, status: :created
end
def update
@post = authorize Posts::Update.new(post_params, @post).execute
render json: @post, serializer: PostSerializer, status: :ok
end
def destroy
authorize Posts::Destroy.new(@post).execute
head :ok
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
@post = Post.find(params[:id])
authorize @post
end
# Only allow a list of trusted parameters through.
def post_params
params.require(:post).permit(:title, :description, :category_id)
end
end
我在动作中使用了一个资源,每一个都有自己的资源,这个是更新动作资源
#resource update.rb
class Posts::Update
attr_accessor :params, :post
def initialize(params, post)
@params = params
@post = post
end
def execute
post.update!(mount_params)
end
private
def mount_params
{
title: params[:title] || post.title,
description: params[:description] || post.description,
category_id: params[:category_id] || post.category_id
}
end
end
有趣的是,create操作在测试时有效,对我来说,它的操作与update操作非常相似
#posts_controller_spec.rb
require 'rails_helper'
require './spec/helpers/authentication_helper'
RSpec.describe PostsController, :focus, type: :controller do
include AuthenticationHelper
include Devise::Test::ControllerHelpers
attr_accessor :post_one, :post_two, :post_three, :user
before(:all) do
posts = FactoryBot.create_list(:post, 3, :with_comments)
@user = FactoryBot.create(:user)
@post_one = posts.first
@post_two = posts.second
@post_three = posts.third
end
let(:valid_headers) do
user.create_new_auth_token
end
let(:root_keys) { %w[post] }
let(:expected_post_keys) { %w[id title description category_id user_id] }
let(:expected_meta_keys) { %w[current_page per_page total_pages total_count] }
let(:error_root_keys) { %w[error] }
let(:expected_error_keys) { %w[message] }
let(:params) do
{
post: {
title: Faker::Quote.yoda,
description: Faker::Lorem.characters(number: 15),
category_id: FactoryBot.create(:category).id
}
}
end
describe 'GET #index' do
let(:root_keys) { %w[posts meta] }
before do
get :index
@body = JSON.parse(response.body)
end
it 'return status code :ok' do
expect(response).to have_http_status(:ok)
end
it 'match with root keys' do
expect(@body.keys).to contain_exactly(*root_keys)
end
it 'match with posts keys' do
@body['posts'].map do |post|
expect(post.keys).to contain_exactly(*expected_post_keys)
end
end
it 'match with meta keys' do
expect(@body['meta'].keys).to contain_exactly(*expected_meta_keys)
end
end
describe 'GET #show' do
context 'when post does not exists' do
let(:root_keys) { %w[error] }
let(:expected_error_keys) { %w[message] }
before do
get :show, params: { id: Faker::Number.number }
@body = JSON.parse(response.body)
end
it 'return status code :not_found' do
expect(response).to have_http_status(:not_found)
end
it 'match with root keys' do
expect(@body.keys).to contain_exactly(*error_root_keys)
end
it 'match with post keys' do
expect(@body['error'].keys).to contain_exactly(*expected_error_keys)
end
end
context 'when post exists' do
let(:expected_post_keys) { %w[id title description category_id user_id comments] }
let(:expected_comment_keys) { %w[id comment post_id created_at] }
before do
get :show, params: { id: post_one.id }
@body = JSON.parse(response.body)
end
it 'return status code :ok' do
expect(response).to have_http_status(:ok)
end
it 'match with root keys' do
expect(@body.keys).to contain_exactly(*root_keys)
end
it 'match with post keys' do
expect(@body['post'].keys).to contain_exactly(*expected_post_keys)
end
it 'match with comment keys' do
@body['post']['comments'].map do |comment|
expect(comment.keys).to contain_exactly(*expected_comment_keys)
end
end
end
end
describe 'POST #create' do
before do # criar um contexto onde o usuario tenta criar um post sem fazer o login
set_authentication_headers_for(user)
post :create, params: params
@body = JSON.parse(response.body)
end
it 'return status code :created' do
expect(response).to have_http_status(:created)
end
it 'match with root keys' do
expect(@body.keys).to contain_exactly(*root_keys)
end
it 'match with post keys' do
expect(@body['post'].keys).to contain_exactly(*expected_post_keys)
end
end
describe 'PUT #update' do
context 'when post does not exists' do
before do
set_authentication_headers_for(user)
put :update, params: params.merge({ id: Faker::Number.number })
@body = JSON.parse(response.body)
end
it 'return status code :not_found' do
expect(response).to have_http_status(:not_found)
end
it 'match with root keys' do
expect(@body.keys).to contain_exactly(*error_root_keys)
end
it 'match with post keys' do
expect(@body['error'].keys).to contain_exactly(*expected_error_keys)
end
end
context 'when post exists' do
before do
set_authentication_headers_for(user)
put :update, params: params.merge({ id: post_one.id })
@body = JSON.parse([response.body].to_json).first
end
it 'return status code :ok' do
expect(response).to have_http_status(:ok)
end
it 'match with root keys' do
expect(@body.keys).to contain_exactly(*root_keys)
end
it 'match with post keys' do
expect(@body['post'].keys).to contain_exactly(*expected_post_keys)
end
end
end
describe 'DESTROY #destroy' do
context 'when post does not exists' do
before do
set_authentication_headers_for(user)
delete :destroy, params: params.merge({ id: Faker::Number.number })
@body = JSON.parse(response.body)
end
it 'return status code :not_found' do
expect(response).to have_http_status(:not_found)
end
it 'match with root keys' do
expect(@body.keys).to contain_exactly(*error_root_keys)
end
it 'match with post keys' do
expect(@body['error'].keys).to contain_exactly(*expected_error_keys)
end
end
context 'when post exists' do
before do
set_authentication_headers_for(user)
delete :destroy, params: { id: post_one.id }
end
it 'return status code :no_content' do
expect(response).to have_http_status(:no_content)
end
end
end
end
PostsController
GET #index
return status code :ok
match with root keys
match with posts keys
match with meta keys
GET #show
when post does not exists
return status code :not_found
match with root keys
match with post keys
when post exists
return status code :ok
match with root keys
match with post keys
match with comment keys
POST #create
return status code :created
match with root keys
match with post keys
PUT #update
when post does not exists
return status code :not_found
match with root keys
match with post keys
when post exists
return status code :ok (FAILED - 1)
match with root keys (FAILED - 2)
match with post keys (FAILED - 3)
DESTROY #destroy
when post does not exists
return status code :not_found
match with root keys
match with post keys
when post exists
return status code :no_content (FAILED - 4)
Failures:
1) PostsController PUT #update when post exists return status code :ok
Failure/Error: expect(response).to have_http_status(:ok)
expected the response to have status code :ok (200) but it was :found (302)
# ./spec/controllers/posts_controllers_spec.rb:163:in `block (4 levels) in <top (required)>'
# ./spec/support/database_cleaner.rb:9:in `block (3 levels) in <main>'
# ./spec/support/database_cleaner.rb:8:in `block (2 levels) in <main>'
2) PostsController PUT #update when post exists match with root keys
Failure/Error: expect(@body.keys).to contain_exactly(*root_keys)
NoMethodError:
undefined method `keys' for #<String:0x0000555e1e849aa0>
# ./spec/controllers/posts_controllers_spec.rb:167:in `block (4 levels) in <top (required)>'
# ./spec/support/database_cleaner.rb:9:in `block (3 levels) in <main>'
# ./spec/support/database_cleaner.rb:8:in `block (2 levels) in <main>'
3) PostsController PUT #update when post exists match with post keys
Failure/Error: expect(@body['post'].keys).to contain_exactly(*expected_post_keys)
NoMethodError:
undefined method `keys' for nil:NilClass
# ./spec/controllers/posts_controllers_spec.rb:171:in `block (4 levels) in <top (required)>'
# ./spec/support/database_cleaner.rb:9:in `block (3 levels) in <main>'
# ./spec/support/database_cleaner.rb:8:in `block (2 levels) in <main>'
4) PostsController DESTROY #destroy when post exists return status code :no_content
Failure/Error: expect(response).to have_http_status(:no_content)
expected the response to have status code :no_content (204) but it was :found (302)
# ./spec/controllers/posts_controllers_spec.rb:204:in `block (4 levels) in <top (required)>'
# ./spec/support/database_cleaner.rb:9:in `block (3 levels) in <main>'
# ./spec/support/database_cleaner.rb:8:in `block (2 levels) in <main>'
Finished in 1.64 seconds (files took 5.32 seconds to load)
24 examples, 4 failures
Failed examples:
rspec ./spec/controllers/posts_controllers_spec.rb:162 # PostsController PUT #update when post exists return status code :ok
rspec ./spec/controllers/posts_controllers_spec.rb:166 # PostsController PUT #update when post exists match with root keys
rspec ./spec/controllers/posts_controllers_spec.rb:170 # PostsController PUT #update when post exists match with post keys
rspec ./spec/controllers/posts_controllers_spec.rb:203 # PostsController DESTROY #destroy when post exists return status code :no_content
我搜索了类似的错误,但我找不到一个可以解决我的问题
1条答案
按热度按时间aydmsdu91#
您正在获得重定向(可能是到登录页面)
我的猜测是,用户无法编辑帖子,因为它不属于他。
我会改变你创建帖子的方式,使其属于用户。
如此多变
进入
也许能解决你的问题
额外的好处:我也会为你现在的情况添加测试:如果用户没有被授权更改一个帖子(无论是更新还是删除),那么它应该被重定向,最重要的是,帖子不会更改(或者不会被删除,这取决于正在测试的操作)