2017-05-18 6 views
1

リファインメント機能を使用してコントローラアクションをスタブすることはできますか?Ruby洗練を使ってテストでのコントローラアクションの動作を変更することは可能ですか?

私は "my_controller_refinement.rb"

require "my_controller" 

module MyControllerRefinement 
    refine MyController do 
    def create_item(my_object = {}) 
     return "test_id" 
    end 
    end 
end 

そして、次のようにテストでそれを使用して洗練を定義しています -

test/ 
    --> my_controller_refinement.rb 
    --> my_controller_test.rb 
- テストdirがようである

require_relative "my_controller_refinement" 

class MyControllerTest < ActionController::TestCase 
    using MyControllerRefinement 

    test "get item" do 
    post :create { my_object: { name: "Test", id: "test_id" } } 
    # Post redirects to the show page 
    assert_redirected_to action: "show", id: "test_id" 
    end 
end 

しかし洗練されていないと実際のコントローラのアクションが呼び出されるようです。

このような「スタブ」には何かが欠けていたり、洗練されていないのですか?

+0

代わりに[模擬ライブラリ](https://www.ruby-toolbox.com/categories/mocking)を使用するほうがよいでしょう。さらに、[ActionController :: TestCaseはRails 5で償却されます](http://blog.bigbinary.com/2016/04/19/changes-to-test-controllers-in-rails-5.html)ので、コントローラーテストでの統合のプログラムを考え直してください。 – max

答えて

1

Refinements現在の作業のため、これは機能しません。ドキュメント(以下に引用)には完全なスクープがありますが、本質的には、洗練のスコープは非常に狭いです。

絞り込みは、クラス、モジュール、またはメソッドのスコープ内ではなく、トップレベルでのみ有効にすることができます。トップレベルで評価されたKernel#evalに渡された文字列で絞り込みを有効にすることができます。絞り込みは、ファイルの終わりまたは評価文字列の終わりまでそれぞれアクティブです。

絞り込みは範囲がレキシカルです。コントロールがスコープの外に転送されると、精細化は無効化されます。これは、現在のスコープの外で定義されたメソッドを呼び出すか、ファイルをロードする必要がある場合、細分化が無効になることを意味します。

+0

私が間違っていると訂正しますが、ドキュメントからはこれが私の理解です 'c.rb - > my_controller.rb、m.rb - > my_controller_refinement.rb、m_user.rb - > my_controller_test.rb' クラスの外で 'using MyControllerRefinement'を動かすことをお勧めしますか? (私もこれを試しましたが、うまくいきませんでした) –

+0

あるいは、 'ActionController :: TestCase'のために、レキシカルスコープが期待通りではないため、洗練されたものが得られませんか? –

+0

"クラス外でMyControllerRefinementを使用して移動することを提案していますか?"いいえ、 "これは動作しません"と開いています。私はあなたがなぜそれが示唆されたかもしれないと思ったのか分かりません。ドキュメントごとに、これはうまくいきません。 1)クラス内の洗練をアクティブにすることはできません.2)別のメソッドを呼び出すと洗練が無効になります。テストから '@controller.new'を直接呼び出しているわけではないので(ライブラリはあります)、リファインメントはアクティブになりません。 – coreyward

0

別の答えが述べているように、改良は、辞書的に、彼らはclassendとの間の空間にのみ有効です意味し、スコープされています。私が例でこれを表示することができますtest_method

class OrigClass 
    def test_method 
    # checks if some methods are defined and calls them if they are 
    puts (!! defined? patch_method_1) && patch_method_1 
    puts (!! defined? patch_method_2) && patch_method_2 
    end 
    # the refinement will attempt to overwrite this method 
    def patch_method_1; 0; end 
end 

puts OrigClass.new.test_method # => 0 false 

module Refinement 
    refine OrigClass do 
    # this method is already defined on OrigClass 
    def patch_method_1; 1; end 
    # this one is not 
    def patch_method_2; 2; end 
    end 
end 

# re-open the class to add the refinement 
class OrigClass 
    using Refinement 
    puts new.test_method # => 0 false 
    puts new.patch_method_1 # => 1 
    puts new.patch_method_2 # => 2 
end 

puts OrigClass.new.test_method # => 0 false 

最後の2つのコールがあるためレキシカルスコープの精製方法を使用しないでください。これはあなたの正確なユースケース(コントローラのアクション)を使用していませんが、それは同じコンセプトであり、洗練はこのように使用することが難しいことを示しています。

+0

いいえ、@ max-pleanerの例ですが、彼らは彼らが想定しているように行動していると思います! クラスを再オープンした時点で、クラスの名前を「OrigClassTest」とし、 'OrigClass.new.patch_method_1'を実行すると、洗練されたものが表示されます。 私の例ではリファインメントを追加するクラスの再オープンは、リファインメントを使用したテストに対応します。 –

+0

おそらく、私が見逃しているのは、テストがスーパークラス 'ActionController :: TestCase'で生成される方法です。コントローラの動作を洗練する方法を再考する必要があります。 –

+1

問題は、あなたのテストケースが、洗練されたメソッドを明示的に呼び出さないということです。おそらくどこかの裏で呼ばれているので、洗練は有効にならないでしょう。 –

関連する問題