0

スタブ/モックは初めてです。

ライブラリを実際に呼び出さずにモジュールのメソッドのみをテストできるように、外部ライブラリからメソッドをスタブするにはどうすればよいですか?

また、このモジュールを作成するための私のアプローチは正しいのでしょうか、それともプログラミングの重要な原則に違反しているのでしょうか?

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

  @ftp = nil

  def self.login    
    if !@ftp || @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  
4

1 に答える 1

3

これを考える最も簡単な方法は、Dependency Injectionの原則を使用することです。テストしているクラスに外部依存関係を渡すことができます。この場合、@ftp オブジェクトです。

クラス(または静的)メソッドとともにオブジェクトでメンバー変数を使用している場合、1つのエラーが発生しています。

クラスを次のように変更することを検討してください。

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

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

  def login    
    if !@ftp || @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 オブジェクトに期待値をスタブまたは設定できます。

注: これを行うには多くの方法がありますが、これは非常に理にかなっている良い例です。外部サービスを抽出して、2倍にしてモック機能に置き換えることができます。

クラス メソッドをスタブ化して、次のようなことを行うこともできます。

Net::FTP.any_instance.stub

何が起こっているのか、より快適になったとき。

于 2013-06-25T14:17:44.403 に答える