web-dev-qa-db-ja.com

プライベートメソッドを指定する方法

RSpecでスペックしたいプライベートメソッドのモデルを取得しました。
通常はどのようにしていますか?プライベートメソッドを呼び出すメソッドのみをテストしますか?
またはプライベートのものも指定しますか?もしそうなら、あなたはどうしますか?

54
Mike

私は常にこのアプローチをとります:私のクラスが公開しているパブリックAPIをテストしたいと思います。

プライベートメソッドがある場合、他のクラスに公開するパブリックメソッドからのみそれらを呼び出します。したがって、これらのパブリックメソッドがすべての条件下で期待どおりに機能することをテストすると、それらが使用するプライベートメソッドも機能することが証明されます。

特に複雑なプライベートメソッドに遭遇したことを認めます。それらをテストしたい極端なケースでは、これを行うことができます:

@obj.send(:private_method)
117
Ariejan

(一時的または永続的に)コードカバレッジを必要とするプライベートメソッドの場合、 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

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

class Example
  private def foo
    'bar'
  end
end

describe Example, :private do
  it 'can test private methods' do
    expect(subject.foo).not eq 'bar'
  end
end
6
barelyknown

プライベートメソッドで期待値をテストしたい場合、受け入れられた答えは実際には機能しません(少なくとも、私が知っていることではないので、その点については修正の余地があります)。代わりに私がやったことはさらに不潔です-テスト自体では、メソッドを再定義してメソッドを公開するだけです:

def object_to_test.my_private_method
  super
end

Ruby 1.8で動作します。新しいランタイムにはコメントできません。

0
Nathan Crause