51800
プロジェクトを管理するサンプルアプリケーションを題材にRSpecの勉強をしています。

サンプルアプリケーションは、プロジェクトを登録することができ、そのプロジェクトは完了済みかどうかのステータス(boolean型のcompleted)を持っています。

プロジェクトの詳細画面には、完了ボタンがあり、完了ボタンを押すと、ステータスが完了済みになります。

この完了ボタンを押すときの、完了処理が失敗したときのフィーチャースペックを書いています。

models/project.rb

```

    class Project < ApplicationRecord
      def complete_pj
        update_attributes(completed: true)
      end
    end
    
```

controllers/projects_controller.rb

```

    class ProjectsController < ApplicationController
      def complete
        if @project.complete_pj
          redirect_to @project, notice: "Congratulations, this project is complete!"
        else
          redirect_to @project, alert: "Unable to complete project."
        end
      end
    end
    
```

spec/features/projects_spec.rb

```

    require 'rails_helper'
    RSpec.feature "Projects", type: :feature do
      scenario "ユーザはプロジェクトを完了済みにする(しかし失敗する)" do
        # 未完了プロジェクトを持ったユーザを準備する
        user = FactoryBot.create(:user)
        project = FactoryBot.create(:project, owner: user, completed: false)
    
        # ユーザはログインしている
        sign_in user
    
        # ユーザがプロジェクト詳細画面を開く。
        visit project_path(project)
    
        # 完了ボタンをクリックする。
        click_button "Complete" # → ここでProjectController#completeアクションが呼ばれる
    
        # 完了処理は失敗し、未完了のままとなる。
        expect(project.reload.completed).to eq false
      end
    end
    
```

完了ボタンを押すことによりProjectController#completeアクションが呼ばれ、その内部で@project.complete_pjが呼ばれます。この「@project.complete_pj」にfalseを返させたいです。

complete_pjメソッドをスタブ化してfalseを返すようにしてやればいいのでは・・・というのは何となくわかるのですが、どうやってコードを書いたらいいかわかりません。

`click_button "Complete"`の前に`allow(project).to
receive(:complete_pj).and_return(false)`を入れるとパスするのでOKかと思いきや、and_return(true)に変えてもパスするので、そもそもスタブ化がうまくできていないようでした。

宜しくお願いします。
CC BY-SA 4.0
2019-01-07T05:25:54.110
51780
2019-01-07T13:11:27.480
2019-01-07T05:52:02.947
question
ruby-on-rails ruby rspec
RSpecのフィーチャースペックでメソッドのスタブ化ができない
`project`オブジェクトの`complete_pj`メソッドに対してstubを適応しており、  
`expect(project.reload.completed).to eq
false`ではstubを未適応の`project.reload.completed`を呼び出しているからではないでしょうか。

以下のような対処があるかと思われます。

  1. `project.reload.completed`にもstubを適応  
ただし、これをするとそもそもテストの意味がなくなってしまうのでは…という懸念もあります

  2. stubを用いるのではなく、fixture等のテストデータで`project.complete_pj`が`false`となるようなデータを用意する  
そこまで複雑なmodelでなければひとまずはこちらのほうが良いかと…
CC BY-SA 4.0
2019-01-07T13:11:27.480
51800
2019-01-07T13:11:27.480
31669
51780
answer