web-dev-qa-db-ja.com

Rspec、Rails:コントローラーのプライベートメソッドをテストする方法は?

私はコントローラーを持っています:

class AccountController < ApplicationController
  def index
  end

  private
  def current_account
    @current_account ||= current_user.account
  end
end

プライベートメソッドをテストする方法current_account rspecで?

追伸Rspec2とRuby on Rails 3

123
petRUShka

#instance_evalを使用

@controller = AccountController.new
@controller.instance_eval{ current_account }   # invoke the private method
@controller.instance_eval{ @current_account }.should eql ... # check the value of the instance variable
191
monocle

Sendメソッドを使用します。例えば:

event.send(:private_method).should == 2

「送信」はプライベートメソッドを呼び出すことができるため

37
graffzon

Current_accountメソッドはどこで使用されていますか?どんな目的に役立ちますか?

通常、プライベートメソッドをテストするのではなく、プライベートメソッドを呼び出すメソッドをテストします。

23
Ryan Bigg

notプライベートメソッドを直接テストする必要があります。パブリックメソッドからコードを実行することで間接的にテストできます。

これにより、テストを変更することなく、コードの内部を変更できます。

8

プライベートまたは保護されたメソッドをパブリックとして作成できます。

MyClass.send(:public, *MyClass.protected_instance_methods) 
MyClass.send(:public, *MyClass.private_instance_methods)

このコードをテストクラスに配置して、クラス名を置き換えてください。該当する場合、名前空間を含めます。

4
zishe
require 'spec_helper'

describe AdminsController do 
  it "-current_account should return correct value" do
    class AccountController
      def test_current_account
        current_account           
      end
    end

    account_constroller = AccountController.new
    account_controller.test_current_account.should be_correct             

   end
end
3
speedingdeer

rspec-context-private gem を使用して、コンテキスト内でプライベートメソッドを一時的にパブリックにします。

gem 'rspec-context-private'

共有コンテキストをプロジェクトに追加することで機能します。

RSpec.shared_context 'private', private: true do

  before :all do
    described_class.class_eval do
      @original_private_instance_methods = private_instance_methods
      public *@original_private_instance_methods
    end
  end

  after :all do
    described_class.class_eval do
      private *@original_private_instance_methods
    end
  end

end

次に、:privateをメタデータとしてdescribeブロックに渡すと、プライベートメソッドはそのコンテキスト内でパブリックになります。

describe AccountController, :private do
  it 'can test private methods' do
    expect{subject.current_account}.not_to raise_error
  end
end
1
barelyknown

プライベートメソッドの単体テストは、アプリケーションの振る舞いのコンテキストから外れすぎています。

最初に呼び出しコードを書いていますか?このコードは、この例では呼び出されません。

動作は、オブジェクトを別のオブジェクトからロードすることです。

context "When I am logged in"
  let(:user) { create(:user) }
  before { login_as user }

  context "with an account"
    let(:account) { create(:account) }
    before { user.update_attribute :account_id, account.id }

    context "viewing the list of accounts" do
      before { get :index }

      it "should load the current users account" do
        assigns(:current_account).should == account
      end
    end
  end
end

なぜあなたが記述しようとしている振る舞いのコンテキストからテストを書きたいのですか?

このコードは多くの場所で使用されますか?より一般的なアプローチが必要ですか?

https://www.relishapp.com/rspec/rspec-Rails/v/2-8/docs/controller-specs/anonymous-controller

1
Brent Greeff

私はこれがちょっとハッキーだと知っていますが、rspecでテストできるがprodでは見えないメソッドが必要な場合に機能します。

class Foo
  def public_method
    #some stuff
  end

  eval('private') unless Rails.env == 'test'

  def testable_private_method
    # You can test me if you set Rails_ENV=test
  end 
end

実行できるようになると、次のような仕様になります。

Rails_ENV=test bundle exec rspec spec/foo_spec.rb 
0
onetwopunch

プライベート関数をテストする必要がある場合は、プライベート関数を呼び出すパブリックメソッドを作成します。

0
liamfriel