82538


勉強とポートフォリオ製作として以下のページを参考にRSpecでテストをしていたのですが、  
User Specテストで詰まってしまいました。

[Rails
チュートリアル（7章）をRSpecでテスト](https://qiita.com/sakakinn/items/41c0f39152c3713fefc4)

解決法をご教授いただければ有難いです。

### やったこと

当初はsignup_pathがundefinedですと怒られていたのですが、QiitaやStackoverflowの記事から
rails_helper.rb内に`config.include
Rails.application.routes.url_helpers`を入れてみたところ、エラーが変化して現状のものになりました。

**環境:**  
Ruby 2.7.4  
Rails 6.0.3

* * *

gemfileのテストの部分は以下です

[code]

    group :development, :test do
      gem 'byebug',            '11.0.1', platforms: [:mri, :mingw, :x64_mingw]
      gem 'factory_bot_rails'
      gem 'rspec-rails',       '~> 5.0'
      gem 'shoulda-matchers'
      gem 'sqlite3',           '1.4.2'
    end
    
    group :test do
      gem 'capybara',                 '3.28.0'
      gem 'guard',                    '2.16.2'
      gem 'guard-minitest',           '2.4.6'
      gem 'minitest',                 '5.11.3'
      gem 'minitest-reporters',       '1.3.8'
      gem 'rails-controller-testing', '1.0.4'
      gem 'selenium-webdriver',       '3.142.4'
      gem 'webdrivers',               '4.1.2'
    end
    
[/code]

rails_helper.rbの主だった中身です

[code]

    require 'spec_helper'
    ENV['RAILS_ENV'] ||= 'test'
    require File.expand_path('../config/environment', __dir__)
    abort("The Rails environment is running in production mode!") if Rails.env.production?
    require 'rspec/rails'
    
    
    begin
      ActiveRecord::Migration.maintain_test_schema!
    rescue ActiveRecord::PendingMigrationError => e
      puts e.to_s.strip
      exit 1
    end
    #capybara内のmethodを読み込む
    require 'capybara/rspec'
    
    RSpec.configure do |config|
      config.fixture_path = "#{::Rails.root}/spec/fixtures"
    
      config.use_transactional_fixtures = true
    
      config.infer_spec_type_from_file_location!
    
      config.filter_rails_from_backtrace!
    
      config.include FactoryBot::Syntax::Methods
      
      config.before(:each, type: :system) do
        driven_by :selenium_chrome_headless
      end
    
      config.include ApplicationHelper
    
      #signup_pathがundefinedと言われたので入れてみた
      config.include Rails.application.routes.url_helpers
    
      #強制的にCapybara::DSLを読み込む
      config.include Capybara::DSL
    end
    
    Shoulda::Matchers.configure do |config|
      config.integrate do |with|
        with.test_framework :rspec
        with.library :rails
      end
    end
    
[/code]

spec/factories/users.rbの中身です

[code]

    FactoryBot.define do
      factory :user do
        name { 'Example User' }
        sequence(:email) { |n| "user_#{n}@example.com" }
        password { 'password' }
        password_confirmation { 'password' }
      end
    end
    
[/code]

問題のspec/models/user_spec.rbの該当箇所です

[code]

    require 'rails_helper'
    
    RSpec.describe User, type: :model do
      
      # factory botが存在するかのテスト
      it 'has a valid factory bot' do
        expect(build(:user)).to be_valid
      end
    
    (中略)
    
      describe 'POST #create' do
        #有効なユーザーの検証
        context 'valid request' do
          #ユーザー追加される
          it 'adds a user' do
            expect do
              # 下のpostがundefinedと言われる
              post signup_path, params: { user: attributes_for(:user) }
            end.to change(User, :count).by(1)
          end
          #ユーザーが追加された時の検証
          context 'adds a user' do
    　　　　　　　　　　　　　　　　# 下のpostがundefinedと言われる
            before { post signup_path, params: { user: attributes_for(:user) } }
            subject { response }
            #showページへリダイレクトされる
            it { is_expected.to redirect_to user_path(User.last) } 
            #リダイレクト成功
            it { is_expected.to have_http_status 302 }
          end
        end
        #無効なリクエスト
        context 'invalid request' do
          #無効なデータの作成
          let(:user_params) do
            attributes_for(:user, name: '',
                                  email: 'user@invalid',
                                  password: '',
                                  password_confirmation: '')
          end
          #ユーザーが追加されないことの検証
          it 'does not add a user' do
            expect do
    　　　　　　　　　　　　　　　　　　　　# 下のpostがundefinedと言われる
              post signup_path, params: { user: user_params }
            end.to change(User, :count).by(0)
          end
        end
      end
    end
    
[/code]

ターミナルで表示されるエラー内容は以下です。

[code]

    User
      has a valid factory bot
      validations
        is expected to validate that :name cannot be empty/falsy
        is expected to validate that :email cannot be empty/falsy
        is expected to validate that the length of :name is at most 50
        is expected to validate that the length of :email is at most 255
        is expected to allow :email to be ‹"first.last@foo.jp"›、‹"user@example.com"›、‹"USER@foo.COM"›、‹"A_US-ER@foo.bar.org"›, or ‹"alice+bob@baz.cn"›
        is expected not to allow :email to be ‹"user@example,com"›、‹"user_at_foo.org"›、‹"user.name@example."›、‹"foo@bar_baz.com"›, or ‹"foo@bar+baz.com"›
        validate uniqueness of email
          is invalid with a duplicate email
      before_save
        #email_downcase
          makes email to low case
      validatetions
        is expected to validate that the length of :password is at least 6
        validate presence of password
          is invalid with a blank password
      POST #create
        valid request
          adds a user (FAILED - 1)
          adds a user
            example at ./spec/models/user_spec.rb:73 (FAILED - 2)
            example at ./spec/models/user_spec.rb:75 (FAILED - 3)
        invalid request
          does not add a user (FAILED - 4)
    
    Failures:
    
      1) User POST #create valid request adds a user
         Failure/Error: post signup_path, params: { user: attributes_for(:user) }
         
         NoMethodError:
           undefined method `post' for #<RSpec::ExampleGroups::User::POSTCreate::ValidRequest:0x00007fa90a96e0f0>
         # ./spec/models/user_spec.rb:65:in `block (5 levels) in <main>'
         # ./spec/models/user_spec.rb:64:in `block (4 levels) in <main>'
    
      2) User POST #create valid request adds a user 
         Failure/Error: before { post signup_path, params: { user: attributes_for(:user) } }
         
         NoMethodError:
           undefined method `post' for #<RSpec::ExampleGroups::User::POSTCreate::ValidRequest::AddsAUser:0x00007fa90a98e828>
         # ./spec/models/user_spec.rb:70:in `block (5 levels) in <main>'
    
      3) User POST #create valid request adds a user 
         Failure/Error: before { post signup_path, params: { user: attributes_for(:user) } }
         
         NoMethodError:
           undefined method `post' for #<RSpec::ExampleGroups::User::POSTCreate::ValidRequest::AddsAUser:0x00007fa8fe3e9988>
         # ./spec/models/user_spec.rb:70:in `block (5 levels) in <main>'
    
      4) User POST #create invalid request does not add a user
         Failure/Error: post signup_path, params: { user: user_params }
         
         NoMethodError:
           undefined method `post' for #<RSpec::ExampleGroups::User::POSTCreate::InvalidRequest:0x00007fa8fe3f00d0>
         # ./spec/models/user_spec.rb:90:in `block (5 levels) in <main>'
         # ./spec/models/user_spec.rb:89:in `block (4 levels) in <main>'
    
    Finished in 0.39295 seconds (files took 2.59 seconds to load)
    15 examples, 4 failures
    
    Failed examples:
    
    rspec ./spec/models/user_spec.rb:63 # User POST #create valid request adds a user
    rspec ./spec/models/user_spec.rb:73 # User POST #create valid request adds a user 
    rspec ./spec/models/user_spec.rb:75 # User POST #create valid request adds a user 
    rspec ./spec/models/user_spec.rb:88 # User POST #create invalid request does not add a user
    
[/code]


CC BY-SA 4.0
2021-09-16T02:36:31.800
82526
2021-09-17T01:36:18.620
2021-09-17T01:36:18.620
48234
48234
question
ruby-on-rails ruby rspec
RSpec でNoMethodError: undefined method 'post' for #<RSpec::....でハマっています


このテストはモデルの単体テスト ([model spec](https://relishapp.com/rspec/rspec-
rails/docs/model-specs)) を行うことが期待されています。一方で RSpec の用意する `post` などの DSL は
request spec で使われることが想定されています。

[code]

    RSpec.describe User, type: :model do
                               ^^^^^^  ここです
    
[/code]

このため、どんなテストがしたかったのかによって対処法が変わります。

モデルの単体テストがしたかったのであれば、`post` を使うのはおかしいです。モデルのメソッドをそのまま呼び出し、その挙動を検査してください。

ルーティングまでを含めた結合テスト、つまり request spec がしたかったのであれば、ドキュメント
<https://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec>
にあるようにテストの定義の仕方を見直してください。


CC BY-SA 4.0
2021-09-16T10:50:20.487
82538
2021-09-16T10:50:20.487
19110
82526
answer