2011-10-09 2 views
2

"extends"메소드를 통해 모델 인스턴스에 포함 된 데코레이터 모듈을 사용합니다. 그래서 예를 들면 :"instance.extend (DecoratorModule)"에 포함 된 메소드 조롱/스텁

module Decorator 
    def foo 
    end 
end 

class Model < ActiveRecord::Base 
end 

class ModelsController < ApplicationController 
    def bar 
    @model = Model.find(params[:id]) 
    @model.extend(Decorator) 
    @model.foo 
    end 
end 

가 그럼 난 다음 (사용 모카)을 수행 할 테스트에 싶습니다

test "bar" do 
    Model.any_instance.expects(:foo).returns("bar") 
    get :bar 
end 

어떻게 든이 가능하거나 할 당신은 마음에 얻을 수있는 다른 방법이 이 기능 ??? (렌더링과 테스트 응용 프로그램에서 확인 : 텍스트)이 작동

답변

1

나는 보통 (대신 런타임을 확장하는) 장식을 포함하고 그것이 나쁜 관행 (I 대신 찾을 조롱) 간주하기 때문에 나는 any_instance을 피하십시오.

module Decorators 
    module Test 
    def foo 
     "foo" 
    end 
    end 
end 

class MoufesController < ApplicationController 

    def bar 
    @moufa = Moufa.first 
    @moufa.extend(Decorators::Test) 
    render :text => @moufa.foo 
    end 
end 

require 'test_helper' 

class MoufesControllerTest < ActionController::TestCase 
    # Replace this with your real tests. 
    test "bar" do 
    m = Moufa.first 
    Moufa.expects(:find).returns(m) 
    m.expects(:foo).returns("foobar") 

    get :bar, {:id => 32} 
    assert_equal @response.body, "foobar" 
    end 
end 
+0

당신은 include vs extend에 대해 옳을 수도 있지만 경우에 따라 클래스의 모든 인스턴스를 확장하고 싶지 않을 수도 있습니다. 어떤 모카 버전을 사용하고 있습니까? 내 컴퓨터에서 오류가 발생합니다 (모카 오류) –

+0

모카 0.10.0을 사용하고 있습니다. 코드 체크 아웃 https://gist.github.com/1277344 – bandito

+0

글쎄, 위의 대답을 읽고, 나는 문제가 any_instance (나는 any_instance를 전혀 사용하지 않고, RSpec에도 존재하지 않는다고 생각한다) – bandito

0

하나의 작은 변화 당신의 반환 값을 테스트하려는 경우 : 바 -

test "bar" do 
    Model.any_instance.expects(:foo).returns("bar") 
    assert_equal "bar", get(:bar) 
end 

을 그냥 모델 인스턴스가 장식 방법 (들)가 있는지 테스트하는 경우에, 정말 당신을 그걸 시험 할 필요가 있니? 이 경우 Object # extend를 테스트하는 것처럼 보입니다.

는 @의 model.foo의 동작을 테스트 할 경우, 통합 테스트에서이 작업을 수행 할 필요가 없습니다가 - 즉, 데코레이터의 장점, 당신은 다음

x = Object.new.extend(Decorator) 
#.... assert something about x.foo ... 
처럼 고립을 테스트 할 수 있습니다

통합 테스트에서의 조롱은 대개 코드 냄새입니다.

+0

아니요, 컨트롤러 동작의 반환 값을 테스트하고 싶지 않습니다. 난 그냥 확장 된 방법 모의하고 테스트 개체에 대한 실제 작업 (외부 호출) "잘라 내기"싶습니다. 모카가이 개체와의 상호 작용을 기록하지 못합니다. –

1

그냥 가정 참고 : 데코레이터 foo 메서드는 전송 한 코드에 표시되지 않는 "바"를 반환한다고 가정합니다. 만약 내가 이것을 가정하지 않는다면, 메소드는 "bar"가 아닌 nil을 반환하기 때문에 어쨌든 기대는 실패 할 것입니다.

위와 같이 가정하면 새로운 레일 애플리케이션을 사용하여 전체 스토리를 시험해 본 결과이 작업을 수행 할 수 없음을 깨달았습니다. 이는 'foo'메소드가 이 아니기 때문에 모델이 모델에 이 예상 될 때 메소드가 테스트에서 호출 될 것이기 때문입니다.

을 기대하고있는 반면,이 결론은 호출 된 메소드 스택을 따라 가려고했습니다. 모카 :: ClassMethod, * hide_original_method * 에서 모카 :: AnyInstanceMethod 호출에 스텁를 호출 모카 :: 중앙 전화 스텁을 기대하고있다. hide_original_method *는 숨길 메소드를 찾지 않으며 아무 것도하지 않습니다. 그런 다음 Model.foo 메서드는 모조 기대치를 구현하기 위해 호출해야하는 스텁 모카 메서드의 별칭이 아니지만 실제로는 Model.foo 메서드가 호출됩니다.이 메서드는 모델 인스턴스에 제어 장치.

내 대답은 그것을 할 수 없다는 것입니다.

+0

이것은 도움이되며 실제로 이것은 문제의 원인입니다. 나는 이것을 실제로 할 수있는 방법이 있는지 모카 개발자들에게 묻고 싶다. 관련 토론에서 모듈 방법을 조롱하는 것이 가능하지 않지만 명시 적으로 말했습니다. Only classes ones ... : ( –

1

이제 알았습니다. 외부 서비스에 대한 호출을 스태핑하고 싶습니다. 재미있는 모카는 이런 방식으로 확장되지 않습니다. 위에서 언급 한 것 외에도 stubbed 메소드가 모듈이 아닌 싱글 톤 클래스에 정의되어 있으므로 혼합되지 않습니다.

왜 이런 식으로하지 않습니까? 어쨌든 일어나고 어떤 커플 링이 있다는 힌트 - - 당신이 아니라 이미 정의 된 데코레이터에 대한 경고를하지 싶다면

test "bar" do 
    Decorator = Module.new{ def foo; 'foo'; end } 
    get :bar 
end 

당신은 그것을 주입 할 수

class ModelsController < ApplicationController 
    class << self 
    attr_writer :decorator_class 
    def decorator_class; @decorator_class ||= Decorator; end 
    end 

    def bar 
    @model = Model.find(params[:id]) 
    @model.extend(self.class.decorator_class) 
    @model.foo 
    end 
end 

는합니다 같은 테스트 : 여러 방법을 정의하는 여러 장식, 또는 장식이있는 더 복잡한 상황이있는 경우 물론

test "bar" do 
    dummy = Module.new{ def foo; 'foo'; end } 
    ModelsController.decorator_class = dummy 
    get :bar 
end 

는이 당신을 위해 작동하지 않을 수 있습니다.

하지만 검색을 스터 빙하는 것이 낫다고 생각합니다. 일반적으로 통합 테스트에서 모델을 스텁하려는 것은 아닙니다.

+0

답장을 보내 주신 에릭에게 감사드립니다.이게 실제로 제가 이미하고있는 것입니다. (거의). 기본적으로이 bandito의 응답은 실제로 작동하는 두 가지 옵션입니다. –

관련 문제