2013-06-30 5 views
2

그래서 나는이 간단한 루비 클래스가 있습니다인스턴스 변수에서 메소드를 스텁하는 방법은 무엇입니까?

class GetRequestList 
    def initialize(current_user, filter_hash) 
    @authorizer = RequestAuthorizer.new(current_user) 
    @filter = RequestFilter.new(filter_hash) 
    end 
    def generate 
    Request.send_chain(@authorizer.method_chain) 
      .send_chain(@filter.method_chain) 
    end 
end 

을 그리고 RequestRequestAuthorizerRequestFilter 구현의 분리에서 두 send_chain 방법을 수신 테스트하려는. 이를 위해 일부 스텁을 사용하려고합니다.

require 'test_helper' 

class GetRequestListTest < ActiveSupport::TestCase 

    test "request should be filtered by filter and role" do 
    Request.expects(:send_chain).twice.returns([build(:request)]) 
    RequestFilter.stubs(:new) 
    RequestFilter.any_instance.stubs(:method_chain).returns([]) 
    RequestAuthorizer.stubs(:new) 
    RequestAuthorizer.any_instance.stubs(:method_chain).returns([]) 
    assert GetRequestList.new(:current_user, :filter).generate.size == 1 
    end 
end 

잘못된 것이 있습니다. stubs(:new)nil을 반환하며 인스턴스 변수 GetRequestList에는 RequestAuthorizerRequestFilter의 인스턴스가 없으므로 오류가 발생합니다. 인스턴스 변수에서 메소드를 스텁하는 방법을 이해할 수 없습니다. 제안 사항이 있으십니까?

+1

'초기화':'@ athorizer' 대'@ authorizer'에 오타가있는 것 같습니다. –

+1

감사합니다. 질문이 남아 있습니다. – lompy

답변

3

new을 스텁 아웃하지 않고 값을 반환하지 말고 반환합니다. 단지 대신 mock_request_filter에 그들을 설정 -

mock_request_filter = mock() 
RequestFilter.stubs(:new).returns(mock_filter) 

이 또한 any_instance에 스텁 읽을 얻을 수 있습니다.

+0

빠른 답장을 보내 주셔서 감사합니다. 'method_chain_mocker = mock (method_chain : []) '으로 해결되었지만 이스마엘 응답도 시도 할 것입니다. – lompy

1

이 때문에 인스턴스 변수를 메서드 내에 래핑해야합니다. 이 접근법을 살펴보십시오. 이렇게하면 RequestFilter 또는 RequestAuthorizer에 대한 테스트가 수행되지 않습니다. 이제는 매개 변수로 사용하는 것이 좋습니다. 메서드 내에서 승인 자 및 필터 초기화도 래핑했습니다. 메인 이니셜 라이저 메소드가 더 많은 정보를 얻는다면 또 다른 하나의 래핑 할 수 있습니다. 당신도 모의 객체로 그들을 필요로하지 않기 때문에

class GetRequestList 
    def initialize(current_user, filter_hash) 
    initialize_authorizer 
    initialize_filter 
    end 

    def generate 
    Request.send_chain(authorizer_method_chain) 
      .send_chain(filter_method_chain) 
    end 

    private 

    def initialize_authorizer 
    @authorizer = RequestAuthorizer.new(current_user) 
    end 

    def initialize_filter 
    @filter = RequestFilter.new(filter_hash) 
    end 

    def authorizer_method_chain 
    @authorizer.method_chain 
    end 

    def filter_method_chain 
    @filter.method_chain 
    end 
end 

시험

require 'test_helper' 

class GetRequestListTest < ActiveSupport::TestCase 

    test "request should be filtered by filter and role" do 
    get_request_list = GetRequestList.new(:current_user, :filter) 
    get_request_list.stubs(:initialize_authorizer) 
    get_request_list.stubs(:initialize_filter) 

    get_request_list.stubs(:authorizer_method_chain).returns(:authorizer_method_chain) 
    get_request_list.stubs(:filter_method_chain).returns(:filter_method_chain) 

    Request.expects(:send_chain).with(:authorizer_method_chain).returns([build(:request)]) 
    Request.expects(:send_chain).with(:filter_method_chain).returns([build(:request)]) 

    assert get_request_list.generate.size == 1 
    end 
end 

나는 또한 권한 부여 및 필터 객체를 대체 할 기호를 사용했다. 12과 같은 다른 것도있을 수 있지만 기호 나 문자열을 유지하면 일을 적절하게 명명 할 수 있습니다.

+0

솔루션은 current_user 및 filter_hash를 새 초기화 프로그램에 전달해야합니다. 어느 쪽이든, 나는이 '방법은 한 가지를하는 것'에 대해 생각해 보았습니다. 그러나 변수를 할당하고 메서드를 호출하기에는 너무 많은 선이 아닙니다. 그리고 왜 GetRequestList 클래스의 본질이라면 내 테스트에서 this 객체에 대해 알지 않아야합니다 : 그 둘을 초기화하고 메소드를 호출 할 수 있습니까? – lompy

+0

또한 Request는 send_chain의 호출을 한 번만 기대하며 Array가 내 오류를 반환하기 때문에 발생합니다. – lompy

+0

단위 테스트가 가능한 가장 작은 것에 집중하기를 원합니다. 그래서 당신은 다른 클래스 이름에 대한 지식으로 그들을 팽창시키고 싶지 않습니다. 이 지식을 방법 안에 보관하는 것이 좋은 해결책 인 것 같습니다. –

0

인스턴스 변수를 스텁 가능하도록 노출 했습니까?

GetRequestList.new(:current_user, :filter).tap do |it| 
    def it.authorizer 
    @authorizer 
    end 
    install_stubs(it.authorizer) 
end.generate 
관련 문제