是否有一种优雅的方法来测试一个实例方法是否是另一个实例的别名?

时间:2010-10-06 05:21:18

标签: ruby reflection alias-method

在单元测试中,我需要测试alias_method定义的别名方法是否已正确定义。我可以简单地对用于原始的别名使用相同的测试,但我想知道是否有更明确或有效的解决方案。例如,有没有办法1)取消引用方法别名并返回其原始名称,2)获取并比较某种基础方法标识符或地址,或3)获取和比较方法定义?例如:

class MyClass
  def foo
    # do something
  end

  alias_method :bar, :foo
end

describe MyClass do
  it "method bar should be an alias for method foo" do
    m = MyClass.new
    # ??? identity(m.bar).should == identity(m.foo) ???
  end
end

建议?

3 个答案:

答案 0 :(得分:18)

根据Method的文档,

  

如果是,则两个方法对象相等   绑定到同一个对象和   包含相同的身体。

调用Object#method并比较它返回的Method个对象将验证方法是否等效:

m.method(:bar) == m.method(:foo)

答案 1 :(得分:3)

bk1e的方法大部分时间都有效,但我碰巧遇到了不起作用的情况:

class Stream
  class << self
    alias_method :open, :new
  end
end

open = Stream.method(:open)
new = Stream.method(:new)
p open, new                   # => #<Method: Stream.new>, #<Method: Class#new>
p open.receiver, new.receiver # => Stream, Stream
p open == new                 # => false

输出是在Ruby 1.9中生成的,不确定它是否是一个bug,因为Ruby 1.8为最后一行产生了true。因此,如果您使用的是1.9,请注意,如果您对继承的类方法(如Class#new)进行别名,则这两个方法绑定到同一个对象(类对象Stream),但它们被认为不是相当于Ruby 1.9。

我的解决方法很简单 - 再次对原始方法进行别名并测试两个别名的相等性:

class << Stream; alias_method :alias_test_open, :new; end
open = Stream.method(:open)
alias_test_open = Stream.method(:alias_test_open)
p open, alias_test_open                   # => #<Method: Stream.new>, #<Method: Stream.new>
p open.receiver, alias_test_open.receiver # => Stream, Stream
p open == alias_test_open                 # => true

希望这有帮助。

<强>更新

请参阅http://bugs.ruby-lang.org/issues/7613

所以Method#==在这种情况下应该返回false,因为super调用会调用不同的方法;这不是一个错误。

答案 2 :(得分:1)

调用MyClass.instance_method(:foo)会产生UnboundMethod个实例,其中包含eql?方法。

所以答案是:

describe MyClass do
  subject { described_class }

  specify do
    expect(subject.instance_method(:foo)).to be_eql(subject.instance_method(:bar))
  end
end