11

を呼び出す Ruby で記述したコードの単体テストを試みていますFile.open。それを嘲笑するために、私File.openは次のようにモンキーパッチを適用しました:

class File
  def self.open(name, &block)
    if name.include?("retval")
      return "0\n"
    else
      return "1\n"
    end
  end
end

問題は、File.open を使用してコード カバレッジ情報を書き込むため、rcov を使用してこのすべてを実行していることです。実際のバージョンではなく、サルのパッチを適用したバージョンを取得します。このメソッドのモンキーパッチを解除して、元のメソッドに戻すにはどうすればよいですか? をいじってみましたが、今のところ役に立ちaliasません。

4

5 に答える 5

19

@Tiloの回答を拡張し、エイリアスを再度使用してモンキーパッチを元に戻します。

例:

# Original definition
class Foo
  def one()
    1
  end
end

foo = Foo.new
foo.one

# Monkey patch to 2
class Foo
  alias old_one one
  def one()
    2
  end
end

foo.one

# Revert monkey patch
class Foo
  alias one old_one
end

foo.one
于 2011-10-25T20:31:30.493 に答える
3

または、スタブ フレームワーク (rspec や mocha など) を使用して、File.Open メソッドをスタブすることもできます。

File.stub(:open => "0\n")

于 2011-10-25T17:13:12.973 に答える
2

次のように簡単にエイリアスできます。

alias new_name old_name

例えば:

class File
  alias old_open open

  def open
    ...
  end
end

File.old_open を介して元の File.open メソッドにアクセスできるようになりました


または、次のようなことを試すこともできます。

ruby - メソッドをオーバーライドしてから元に戻す

http://blog.jayfields.com/2006/12/ruby-alias-method-alternative.html

于 2011-10-25T17:42:16.170 に答える
2

Fileのインスタンスを保持する単なる定数ですClass。に応答する一時クラスに設定してから、open元のクラスを復元​​できます。

original_file = File
begin
  File = Class.new             # warning: already initialized constant File
  def File.open(name, &block)
    # Implement method
  end
  # Run test
ensure
  File = original_file         # warning: already initialized constant File
end
于 2011-10-25T17:04:17.920 に答える
1

これを行う正しい方法は、Dan が言うようにスタブ フレームワークを実際に使用することです。

たとえば、rspec では次のようにします。

it "reads the file contents" do
  File.should_receive(:open) {|name|
    if name.include?("retval")
      "0\n"
    else
      "1\n"
    end
  }
  File.open("foo retval").should == "0\n"
  File.open("other file").should == "1\n"
end

しかし、好奇心旺盛な人のために、外部ライブラリなしでそれを行う半安全な方法を次に示します。考えられるのは、スタブによって影響を受けるコードができるだけ少なくなるように、スタブを分離することです。

このスクリプトにisolated-patch.rb次の名前を付けました。

class File
  class << self
    alias_method :orig_open, :open

    def stubbed_open(name, &block)
      if name.include?("retval")
        return "0\n"
      else
        return "1\n"
      end
    end
  end
end


def get_size(path)
  # contrived example
  File.open(path) {|fh|
    # change bytesize to size on ruby 1.8
    fh.read.bytesize
  }
end

# The stub will apply for the duration of the block.
# That means the block shouldn't be calling any methods where file opening
#   needs to work normally.
# Warning: not thread-safe
def stub_file_open
  class << File
    alias_method :open, :stubbed_open
  end
  yield
ensure
  class << File
    alias_method :open, :orig_open
  end
end

if __FILE__ == $0
  stub_file_open do
    val = File.open("what-retval") { puts "this is not run" }
    puts "stubbed open() returned: #{val.inspect}"
    size = get_size("test.txt")
    puts "obviously wrong size of test.txt: #{size.inspect}"
  end

  # you need to manually create this file before running the script
  size = get_size("test.txt")
  puts "size of test.txt: #{size.inspect}"
end

デモ:

> echo 'foo bar' > test.txt
> ruby isolated-patch.rb
stubbed open() returned: "0\n"
obviously wrong size of test.txt: "1\n"
size of test.txt: 8
于 2012-09-28T18:21:39.027 に答える