19641


rspec2.99でテスト全部ok後transpecを実行しました。以下ワーニングが出るようになりました。

[code]

    Matching with be_hoge_fixed on an object that doesn't respond to `hoge_fixed?` is deprecated. Use `respond_to_missing?` or `respond_to?` on your object instead. Called from /hoge/poge/workspace/transpec4.0/spec/controllers/hogehoge/hoges_controller_spec.rb:207:in `block (5 levels) in <top (required)>'.
    
[/code]

テストコードは以下の感じです。

[code]

    context "かつ、情報が存在しない場合、" do
      before(:each) do
        Pogepoge.stub_chain(:hoge_at, :exists?){false}
      end
      it "falseを返す" do
        expect(controller).not_to be_hoge_fixed
      end
    end
    
[/code]

プロダクトコードは以下のようです。

[code]

    def hoge_fixed?
      return false unless poge_selected?
      unless HOGE.exists?
        return false
      end
      true
    end
    
    
    def poge_selected?
      if params[:poge_month].blank?
        return false
      end
      true
    end
    
[/code]

ワーニング解消方法を知りたいです。


CC BY-SA 3.0
2015-12-04T14:30:24.037
19637
2015-12-04T21:51:02.067
10851
question
ruby-on-rails ruby rspec
transpecで実行後is deprecated. Use `respond_to_missing?` or `respond_to?` on your object instead.が出る


警告が出る原因を端的に言うと、おそらく`hoge_fixed?`がprivateメソッドになっているせいです。

警告文は以下のコードで出力されています。

<https://github.com/rspec/rspec-
expectations/blob/2-99-maintenance/lib/rspec/matchers/built_in/be.rb>

[code]

        # ...
    
            @result = actual.__send__(predicate, *@args, &@block)
            check_respond_to(predicate)
    
        # ...
    
        def check_respond_to(method)
          RSpec.deprecate(
            "Matching with #{@prefix}#{@expected} on an object that doesn't respond to `#{method}`",
            :replacement => "`respond_to_missing?` or `respond_to?` on your object"
          ) unless actual.respond_to?(method)
        end
    
[/code]

`__send__`とで呼び出すと値が返るが、`respond_to?`をチェックするとfalseが返る、というのは、Rubyの言語仕様から想像するに、privateメソッドの可能性が高いと思います。

解決策はいくつか考えられます。

  1. 間接的に`hoge_fixed?`をテストする（「`hoge_fixed?`がfalseになるはずなので、`foo_path`にリダイレクトすればOK」、みたいなテストを書く）
  2. `hoge_fixed?` をpublicメソッドにする
  3. `expect(controller.send(:hoge_fixed?)).to be_truthy` のように、privateメソッドを直接呼び出す。

個人的なオススメは1です。  
ネットを見ていると、3のアプローチを紹介している記事もよく見かけます。  
しかし、privateメソッドはprivateメソッドのままにしておき、あくまで「外からは呼び出せないこと」を前提としたテストコードにすべき、というのが僕の考え方です。


CC BY-SA 3.0
2015-12-04T21:51:02.067
19641
2015-12-04T21:51:02.067
85
19637
answer