用户must_send使用一个在minitest中调用super的方法

时间:2014-01-08 23:38:13

标签: ruby unit-testing inheritance ruby-1.9 minitest

假设我有以下模块:

module SillyDemo
   class Monkey
     def screech(sound)
        sound
     end
   end

   class Ape < Monkey
     def process(sound)
       sound
     end
     def screech(sound)
       process(sound)
       super
       sound
     end
   end
end

然后是以下最小的:

   require_relative 'sillydemo'
   require "minitest/spec"
   require "minitest/autorun"

   describe "Ape" do
        before do
           @ape = Ape.new
           @screech = "YEEEEEEE"
        end

        it "screeches" do
            @ape.screech(@screech)
            must_send [@ape, :process, @screech]
            must_send [@ape, :super, @screech]
        end 
     end

这出错了:

NoMethodError: undefined method `super' for #<SillyDemo::Ape:0x007feeb10943c0>
    (eval):4:in `must_send'

我也尝试过:

must_send [@ape, :"SillyDemo::Monkey.screech", @screech]

出错的地方:

NoMethodError: undefined method `SillyDemo::Ape.run' for #<SillyDemo::Ape:0x007fc5a1874e20>
    (eval):4:in `must_send'

我的问题是,如何使用minitest来测试对super的调用?

1 个答案:

答案 0 :(得分:0)

在Ruby super中是关键字,而不是方法。此外,must_send期望不会验证方法是否被调用,它只是验证方法的返回值是否真实。

http://www.ruby-doc.org/stdlib-2.0.0/libdoc/minitest/rdoc/MiniTest/Expectations.html#method-i-must_send http://www.ruby-doc.org/stdlib-2.0.0/libdoc/minitest/rdoc/MiniTest/Assertions.html#method-i-assert_send

模拟通常用于验证方法是否被调用。但是,Minitest :: Mock在设计上不容易进行这种类型的检查。这是你如何做到这一点。

it "screeches" do
  # 1) Create mock
  sound_mock = Minitest::Mock.new
  sound_mock.expect :process, true, [String]

  # 2) Place mock
  @ape.instance_exec(sound_mock) do |sound_mock|
    @mock = sound_mock
    def process sound
      @mock.process sound
    end
  end

  # 3) Verify mock was called
  @ape.screech(@screech)
  sound_mock.verify
end

非常难看,对吗?这是设计的。有点像句法醋。原因是这种模拟的使用并不是很有用。它正在检查代码的实现。您希望能够在不改变行为的情况下重构代码并让测试继续通过。但是,当实现更改时,此测试很可能会失败。为了阻止人们犯这种错误,Minitest的作者决定让这种检查变得困难。

其他模拟库(例如RRMocha)使此类检查变得更加容易。