Ruby on rails 为什么我的rspec测试失败?
我的“创建后”操作有问题。当属性有效时,测试成功通过,但当属性无效时,播放器也被保存。这很奇怪,因为只有:无效的玩家,可以用无效属性保存。例如,如果我更改为-1或“字符串”,则保存属性为:invalid_player的玩家。但若我更改:player的属性,比如wins=-1,验证器将阻止保存player 带有错误消息的控制台输出:Ruby on rails 为什么我的rspec测试失败?,ruby-on-rails,rspec,Ruby On Rails,Rspec,我的“创建后”操作有问题。当属性有效时,测试成功通过,但当属性无效时,播放器也被保存。这很奇怪,因为只有:无效的玩家,可以用无效属性保存。例如,如果我更改为-1或“字符串”,则保存属性为:invalid_player的玩家。但若我更改:player的属性,比如wins=-1,验证器将阻止保存player 带有错误消息的控制台输出: Failures: 1) PlayersController user is signed in POST create with invalid attrib
Failures:
1) PlayersController user is signed in POST create with invalid attributes does not save the new player
Failure/Error:
expect{
post :create, { tournament_id: @tournament, player: FactoryGirl.attributes_for(:invalid_player) }
}.to_not change(Player, :count)
expected #count not to have changed, but did change from 1 to 2
# ./spec/controllers/players_controller_spec.rb:111:in `block (5 levels) in <top (required)>'
规格测试:
context "user is signed in" do
before do
@tournament = create(:tournament)
@player = create(:player)
@user = create(:user)
@request.env["devise.mapping"] = Devise.mappings[:user]
sign_in(@user)
controller.stub(:current_user).and_return(@user)
end
describe "GET new" do
end
describe "GET index" do
it "renders the :index view" do
get :index, tournament_id: @tournament
expect(response).to render_template :index
end
end
describe "GET show" do
it "renders the :show view" do
get :show, { id: @player, tournament_id: @tournament }
expect(response).to render_template :show
end
end
describe "POST create" do
context "with valid attributes" do
it "creates a new player" do
expect{
post :create, { tournament_id: @tournament, player: FactoryGirl.attributes_for(:player) }
}.to change(Player,:count).by(1)
end
it "redirects to the tournament" do
post :create, { tournament_id: @tournament, player: FactoryGirl.attributes_for(:player) }
expect(response).to redirect_to @tournament
end
end
context "with invalid attributes" do
it "does not save the new player" do
expect{
post :create, { tournament_id: @tournament, player: FactoryGirl.attributes_for(:invalid_player) }
}.to_not change(Player, :count)
end
it 're-renders the new method' do
post :create, { tournament_id: @tournament, player: FactoryGirl.attributes_for(:invalid_player) }
response.should render_template :new
end
end
end
end
控制器:
class PlayersController < ApplicationController
before_action :set_tournament
before_action :set_admin, only: [:edit, :update, :destroy]
before_action :authenticate_user!, only: [:new, :create, :edit, :update, :destroy]
def index
@players = @tournament.players.all
end
def show
@player = Player.find(params[:id])
end
def new
@player = @tournament.players.new
end
def create
if current_user.player.nil? == false
flash[:error] = "You're already in tournament."
redirect_to tournaments_url
else
@player = @tournament.players.new
@player.user_id = current_user.id
if @player.save
redirect_to @tournament
else
render 'new'
end
end
end
def edit
if current_user == @admin
@player = @tournament.players.find(params[:id])
else
redirect_to tournaments_url
end
end
def update
if current_user == @admin
@player = @tournament.players.find(params[:id])
if @player.update_attributes(game_params)
flash[:success] = "Player was updated successful"
redirect_to @tournament
end
else
redirect_to tournaments_url
end
end
def destroy
@player = Player.find(params[:id])
flash[:success] = "Player deleted"
redirect_to @tournament
end
private
def set_tournament
@tournament = Tournament.find(params[:tournament_id])
end
def set_admin
@tournament = Tournament.find(params[:tournament_id])
@admin = @tournament.user
end
end
class PlayersController
您没有在创建方法中为模型指定任何属性。您需要执行以下操作(我假设是rails 4):
在没有任何赋值的情况下,您很可能会返回到有效的数据库默认值零。使用
binding.pry
或byebug
进行一些调试。找出实际传递到控制器中的属性以及模型层不拒绝这些属性的原因。尝试打印上次保存的Player。使用put
打印上次保存的,并查看是否保存。通过create
,create进行验证代码>,保存
,保存代码>,更新
和更新代码>。因此,如果你的控制器存储了玩家,它将进入数据库而不进行验证。请发布你的控制器代码。@das-g那么,如果其中一个属性无效,为什么不能保存带有属性:player的玩家?嗯,我有点惭愧。我想,没有必要将这部分代码放在那里,因为player的属性,在我的数据库中设置。还有为什么我的测试有一半是有效的,没有你答案中的代码?@Nekron-出于安全原因,这个代码是必要的-仅仅因为你在数据库中有一列并不意味着它可以从外部世界写入(常见场景-用户模型中的admin列通常只能由其他管理员设置)。由于您的操作不会引发任何异常(但始终在数据库中创建记录),因此其他测试没有失败的理由。
context "user is signed in" do
before do
@tournament = create(:tournament)
@player = create(:player)
@user = create(:user)
@request.env["devise.mapping"] = Devise.mappings[:user]
sign_in(@user)
controller.stub(:current_user).and_return(@user)
end
describe "GET new" do
end
describe "GET index" do
it "renders the :index view" do
get :index, tournament_id: @tournament
expect(response).to render_template :index
end
end
describe "GET show" do
it "renders the :show view" do
get :show, { id: @player, tournament_id: @tournament }
expect(response).to render_template :show
end
end
describe "POST create" do
context "with valid attributes" do
it "creates a new player" do
expect{
post :create, { tournament_id: @tournament, player: FactoryGirl.attributes_for(:player) }
}.to change(Player,:count).by(1)
end
it "redirects to the tournament" do
post :create, { tournament_id: @tournament, player: FactoryGirl.attributes_for(:player) }
expect(response).to redirect_to @tournament
end
end
context "with invalid attributes" do
it "does not save the new player" do
expect{
post :create, { tournament_id: @tournament, player: FactoryGirl.attributes_for(:invalid_player) }
}.to_not change(Player, :count)
end
it 're-renders the new method' do
post :create, { tournament_id: @tournament, player: FactoryGirl.attributes_for(:invalid_player) }
response.should render_template :new
end
end
end
end
class PlayersController < ApplicationController
before_action :set_tournament
before_action :set_admin, only: [:edit, :update, :destroy]
before_action :authenticate_user!, only: [:new, :create, :edit, :update, :destroy]
def index
@players = @tournament.players.all
end
def show
@player = Player.find(params[:id])
end
def new
@player = @tournament.players.new
end
def create
if current_user.player.nil? == false
flash[:error] = "You're already in tournament."
redirect_to tournaments_url
else
@player = @tournament.players.new
@player.user_id = current_user.id
if @player.save
redirect_to @tournament
else
render 'new'
end
end
end
def edit
if current_user == @admin
@player = @tournament.players.find(params[:id])
else
redirect_to tournaments_url
end
end
def update
if current_user == @admin
@player = @tournament.players.find(params[:id])
if @player.update_attributes(game_params)
flash[:success] = "Player was updated successful"
redirect_to @tournament
end
else
redirect_to tournaments_url
end
end
def destroy
@player = Player.find(params[:id])
flash[:success] = "Player deleted"
redirect_to @tournament
end
private
def set_tournament
@tournament = Tournament.find(params[:tournament_id])
end
def set_admin
@tournament = Tournament.find(params[:tournament_id])
@admin = @tournament.user
end
end
@player = @tournament.players.new(player_params)
#...
private
def player_params
params.require(:player).permit(:wins, :loses, :draws)
end