2013-06-25 4 views
0

스텁/조롱을 처음 사용했습니다.타사 라이브러리를 스텁 또는 모방하는 방법

라이브러리를 실제로 호출하지 않고 모듈의 메서드 만 테스트 할 수 있도록 외부 라이브러리에서 메서드를 스텁하는 방법은 무엇입니까?

또한이 모듈을 작성하는 방식이 프로그래밍의 중요한 원칙을 위반하는지 궁금합니다.

# file_module.rb 
module FileModule 
    require 'net/ftp' 

    @ftp = nil 

    def self.login  
    if [email protected] || @ftp.closed? 
     @ftp = Net::FTP.new(Rails.configuration.nielsen_ftp_server) 
     @ftp.login(Rails.configuration.nielsen_ftp_user, Rails.configuration.nielsen_ftp_password) 
    end 
    end 

    def self.get_list_of_files_in_directory(directory, type) 
    login 
    @ftp.chdir("/#{directory}")   
    files = case type 
     when "all"   then @ftp.nlst("*") 
     when "add"   then @ftp.nlst("*add*") 
    end 
    end 
end 

# file_module_spec.rb (RSpec)  
require 'spec_helper' 
describe NielsenFileModule do 
    describe ".get_list_of_files_in_directory" do 
    it "returns correct files for type all" do 
     # how to mock Net::FTP or stub all its methods so I simulate the return value of @ftp.nlst("*")? 
     NielsenFileModule.get_list_of_files_in_directory("test_folder", "all").count.should eq 6 
    end 
    end 
end 

답변

2

가장 쉬운 방법은 Dependency Injection의 원칙을 사용하는 것입니다. 외부 종속성을 테스트중인 클래스에 전달할 수 있습니다. 이 경우 @ftp 객체.

클래스 또는 정적 메서드와 함께 개체의 멤버 변수를 사용하는 경우 하나의 오류가 발생합니다.

다음을 수행하기 위해 클래스를 수정하십시오 : 테스트에서 지금

# file_module.rb 
module FileModule 
    require 'net/ftp' 
    attr_accessor :ftp 

    @ftp = Net::FTP.new(Rails.configuration.nielsen_ftp_server) 

    def login  
    if [email protected] || @ftp.closed? 
     @ftp.login(Rails.configuration.nielsen_ftp_user, Rails.configuration.nielsen_ftp_password) 
    end 
    end 

    def get_list_of_files_in_directory(directory, type) 
    login 
    @ftp.chdir("/#{directory}")   
    files = case type 
     when "all"   then @ftp.nlst("*") 
     when "add"   then @ftp.nlst("*add*") 
    end 
    end 
end 

를, 모듈의 테스트 클래스 메서드, 당신은 모듈의 객체 메소드를 테스트 할 수 있습니다보다는.

require 'spec_helper' 
class FileClass 
    include FileModule 
end 

let(:dummy) { FileClass.new } 
let(:net_ftp) { double(Net::FTP) } 
before { dummy.ftp = net_ftp } 

describe FileModule do 
    describe '.login' do 
    context 'when ftp is not closed' do 
     before { net_ftp.stub(:closed) { true } } 
     it 'should log in' do 
     net_ftp.should_receive(:login).once 
     dummy.login 
     end 
    end 
    end 
end 

이제 위의 그림과 같이 net_ftp 개체에서 스텁을 만들거나 기대치를 설정할 수 있습니다.

참고 :이 작업을 수행하는 방법에는 여러 가지가 있지만, 많은 의미가있는 좋은 예입니다. 외부 서비스를 이중화하여 조롱 된 기능으로 대체 할 수있는 서비스에 압축을 풀고 있습니다.

또한 클래스 메소드를 스텁과 같은 몇 가지 작업을 수행 할 수 있습니다 당신은 무슨 일이 일어나고 있는지 더 편안있을 때

Net::FTP.any_instance.stub 

.

+1

@ gmacdokugall의 접근 방식은 좋지만, 좌절감을 유발할 수있는 코드에 대한 교활한 문제가 있습니다.'file_module.rb'의 6 행에 할당 된'@ ftp' 변수가 같지 않습니다.'@ ftp' 변수를 참조하십시오. '@ ftp'가 할당 될 때'self '는 ** 모듈 **이고 인스턴스 메소드의'self'는 ** 인스턴스 **이므로 두 개의 다른'@ ftp' 변수가 참조됩니다. 하나의 해결책은 이미 정의되지 않은 경우'@ ftp'에 할당하는'ftp'에 대한 "getter"인스턴스 메소드를 갖는 것입니다. –

+0

필자는 항상 테스트를 위해 의존성 주입이 코드 냄새라고 생각했습니다. –

관련 문제