脚手架生成的rspec控制器测试在Factory创建的模型上返回nil

时间:2014-04-14 03:58:06

标签: ruby-on-rails ruby rspec factory-bot

即使以下行在模型测试中运行良好:

game = FactoryGirl.create(:game)

似乎没有在games_controller_rspec.rb上执行此操作。

describe "GET index" do
    it "assigns all games as @games" do
      game = FactoryGirl.create(:game)
      get :index, {}
      expect(assigns(:games)).to eq([game])
    end
end

我一直在预期:[...]             得到了:nil"

这是工厂:

FactoryGirl.define do
  factory :game do |f|
    f.team_a_id { 1 }
    f.team_b_id { 2 }
  end
end

Full games_controller.rb:

class GamesController < ApplicationController
before_action :set_game, only: [:show, :edit, :update, :destroy]
before_filter :check_admin_status, only: [:new, :edit, :create, :update, :destroy]

def index
    @games = Game.all
end

def show
end

def new
    @game = Game.new
end

def edit
end

def create
    @game = Game.new(game_params)

respond_to do |format|
    if @game.save
        format.html { redirect_to @game, notice: 'Game was successfully created.' }
        format.json { render action: 'show', status: :created, location: @game }
    else
        format.html { render action: 'new' }
        format.json { render json: @game.errors, status: :unprocessable_entity }
    end
end

def update
    respond_to do |format|
        if @game.update(game_params)
        format.html { redirect_to @game, notice: 'Game was successfully updated.' }
        format.json { head :no_content }
    else
        format.html { render action: 'edit' }
        format.json { render json: @game.errors, status: :unprocessable_entity }
    end
    end

end

def destroy
    @game.destroy
    respond_to do |format|
      format.html { redirect_to games_url }
      format.json { head :no_content }
    end
  end

private
    def set_game
      @game = Game.find(params[:id])
    end

    def game_params
      params.require(:game).permit(:team_a_id, :team_b_id)
    end
end

完整的games_controller_spec.rb:

require 'spec_helper'

describe GamesController do
  include Devise::TestHelpers

  let(:valid_attributes) { { "team_a_id" => "1" } }
  let(:valid_session) { {} }

  describe "GET index" do
    it "assigns all games as @games" do
      game = FactoryGirl.create(:game)
      get :index, {}
      expect(assigns(:games)).to eq([game])
    end
  end

  describe "GET show" do
    it "assigns the requested game as @game" do
      game = FactoryGirl.create(:game)
      get :show, {:id => game.to_param}, valid_session
      expect(assigns(:game)).to eq(game)
    end
  end

  describe "GET new" do
    it "assigns a new game as @game" do
      get :new, {}, valid_session
      expect(assigns(:game)).to be_a_new(Game)
    end
  end

  describe "GET edit" do
    it "assigns the requested game as @game" do
      game = FactoryGirl.create(:game)
      get :edit, {:id => game.to_param}, valid_session
      expect(assigns(:game)).to eq(game)
    end
  end

  describe "POST create" do
    describe "with valid params" do
      it "creates a new Game" do
        expect {
          post :create, {:game => valid_attributes}, valid_session
        }.to change(Game, :count).by(1)
      end

      it "assigns a newly created game as @game" do
        post :create, {:game => valid_attributes}, valid_session
        expect(assigns(:game)).to be_a(Game)
        expect(assigns(:game)).to be_persisted
      end

      it "redirects to the created game" do
        post :create, {:game => valid_attributes}, valid_session
        expect(response).to redirect_to(Game.last)
      end
    end

    describe "with invalid params" do
      it "assigns a newly created but unsaved game as @game" do
        allow_any_instance_of(Game).to receive(:save).and_return(false)
        post :create, {:game => { "team_a_id" => "invalid value" }}, valid_session
        expect(assigns(:game)).to be_a_new(Game)
      end

      it "re-renders the 'new' template" do
        allow_any_instance_of(Game).to receive(:save).and_return(false)
        post :create, {:game => { "team_a_id" => "invalid value" }}, valid_session
        expect(response).to render_template("new")
      end
    end
  end

  describe "PUT update" do
    describe "with valid params" do
      it "updates the requested game" do
        game = Game.create! valid_attributes
        expect_any_instance_of(Game).to receive(:update).with({ "team_a_id" => "1" })
        put :update, {:id => game.to_param, :game => { "team_a_id" => "1" }}, valid_session
      end

      it "assigns the requested game as @game" do
        game = Game.create! valid_attributes
        put :update, {:id => game.to_param, :game => valid_attributes}, valid_session
        expect(assigns(:game)).to eq(game)
      end

      it "redirects to the game" do
        game = Game.create! valid_attributes
        put :update, {:id => game.to_param, :game => valid_attributes}, valid_session
        expect(response).to redirect_to(game)
      end
    end

    describe "with invalid params" do
      it "assigns the game as @game" do
        game = Game.create! valid_attributes
        allow_any_instance_of(Game).to receive(:save).and_return(false)
        put :update, {:id => game.to_param, :game => { "team_a_id" => "invalid value" }}, valid_session
        expect(assigns(:game)).to eq(game)
      end

      it "re-renders the 'edit' template" do
        game = Game.create! valid_attributes
        allow_any_instance_of(Game).to receive(:save).and_return(false)
        put :update, {:id => game.to_param, :game => { "team_a_id" => "invalid value" }}, valid_session
        expect(response).to render_template("edit")
      end
    end
  end

  describe "DELETE destroy" do
    it "destroys the requested game" do
      game = Game.create! valid_attributes
      expect {
        delete :destroy, {:id => game.to_param}, valid_session
      }.to change(Game, :count).by(-1)
    end

    it "redirects to the games list" do
      game = Game.create! valid_attributes
      delete :destroy, {:id => game.to_param}, valid_session
      expect(response).to redirect_to(games_url)
    end
  end

end

2 个答案:

答案 0 :(得分:3)

找到它。问题在于用户权限。我正在使用设计,只允许常规用户使用某些方法。因此,除非我与管理员用户进行测试,否则他们的结果将为零。 基本上我必须在规范上设置一个管理员用户才能使它工作。

您就是这样做的:

1)在控制器/支持

中写入controller_macros.rb
module ControllerMacros
  def login_admin
    before(:each) do
      @request.env["devise.mapping"] = Devise.mappings[:admin]
      sign_in FactoryGirl.create(:admin) # Using factory girl as an example
    end
  end

  def login_user
    before(:each) do
      @request.env["devise.mapping"] = Devise.mappings[:user]
      user = FactoryGirl.create(:user)
      user.confirm! 
      sign_in user
    end
  end
end

2)将其添加到spec_helper

RSpec.configure do |config|
  config.include Devise::TestHelpers, :type => :controller
  config.extend ControllerMacros, :type => :controller
end

3)在controller_spec上将用户设置为admin

describe GamesController do
    login_admin

    describe "GET index" do
        game = FactoryGirl.create(:game)
        get :index, {}, valid_session
        expect(assigns(:games).to eq([game])
    end

我的用户工厂:

FactoryGirl.define do
    factory :user do
        email "nn@nnn.com"
        password "12345654321"
        password_confirmation { "12345654321" }
        factory :admin do
            after(:create) { |user| user.update_attribute :admin, true }
        end
    end
end

成立here

答案 1 :(得分:1)

我有同样的问题。我在这里发现了一个帖子(我忘了给它添加书签并且找不到它),说要用“controller.index”替换你的“get:index,{}”并查看它是否有效。当我这样做时,它对我有用。他们还说这是一个路由问题。我不明白的是为什么,以及如何解决它,以便我可以使用从脚手架生成的标准代码。我的路由测试通过,但是有一个路由问题导致“get”不能在这些测试中工作?我不明白。

编辑:

刚发现帖子。看看here. OP永远不会回来告诉我们他们如何修复它的问题是什么。我很想知道,因为我试图弄清楚如何使这个工作变得沮丧。