升级至最小5.4.0。现在必须*并且不会在Minitest :: Test子类中工作,但断言*仍然有效

时间:2014-08-10 21:17:37

标签: ruby minitest

我一直在使用Ruby 2.1附带的MiniTest而没有任何问题。我会继承MiniTest :: Unit:TestCase创建一些像'test_simple'这样的方法,一切正常。我会毫无疑问地使用Expectations和Asserts。

我使用gem将Minitest升级到5.4.0。无处不在我使用期望(必须和不可思议)我得到了一个扼杀错误。测试类的示例。

gem 'minitest'
require "minitest/autorun"
require "rest-client"
require "json"
require "pp"
# require './testcase_addins'


class TestUserKey < Minitest::Test

  def test_simple
    data = 0
    assert( data >= 0 )
    data.must_be :>=,0
  end
end

当我运行它时,断言行没有问题,但must_be行抛出此错误:

  1) Error:
TestUserKey#test_simple:
NoMethodError: undefined method `assert_operator' for nil:NilClass
    (eval):4:in `must_be'
    user_key_testcase.rb:14:in `test_simple'

奇怪的部分是什么是nil:错误中的NilClass不能为零;即使我将Fixnum更改为String,我仍然会得到相同的错误。

如果我将测试更改为规格测试,一切都会再次起作用。所以我不能在单元测试中使用Expectations?如果是这样,有人可以解释原因吗?

2 个答案:

答案 0 :(得分:2)

简短的回答是,使用5.4.0,您的测试类必须继承MiniTest :: Spec才能使用期望值。

我在一台新的ubuntu机器上测试了这个,它通过RVM安装了ruby 2.1.2:

rvm install ruby-2.1.2

此代码适用于stock ruby​​ 2.1.2(没有安装5.4.0 minitest gem,从上面的示例代码中略微清理过):

#!/usr/bin/env ruby

require 'minitest/unit'
require "minitest/autorun"

class TestUserKey < MiniTest::Unit::TestCase

  def test_simple
    data = 0
    assert( data >= 0 )
    data.must_be :>=,0
  end

end

运行此代码可以正常运行。要重现上面列出的错误,请安装minitest 5.4.0:

gem install minitest -v 5.4.0

现在代码失败了“NoMethodError:undefined方法`assert_operator'代表nil:NilClass”。您现在安装了两个版本的minitest:

~/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/minitest/  # stock ruby version of minitest
~/.rvm/gems/ruby-2.1.2/gems/minitest-5.4.0/        # minitest v5.4.0 installed via rubygems

现在一切都已建立,我们可以深入了解到底发生了什么。通过调用infect_an_assertion来定义期望,如下所示:

infect_an_assertion :assert_operator, :must_be, :reverse

对于5.4.0,该调用发生在〜/ .rvm / gems / ruby​​-2.1.2 / gems / minitest-5.4.0 / lib / minitest / expectations.rb中。它在两个版本中大致相同,只是在不同的地方发生。

对于这两个版本,

infect_an_assertion也大致相同。对于:must_be它结束了这个调用,这两个版本的minitest是相同的:

MiniTest::Spec.current.#{meth}(args.first, self, *args[1..-1])

他们在这里做了一些元编程,运行时的调用看起来更像是因为meth设置为assert_operator:

MiniTest::Spec.current.assert_operator(...)

重要的部分是MiniTest :: Spec.current。在5.4.0中,此方法返回nil,当它尝试在nil上调用assert_operator时会导致NoMethodError异常。

来自红宝石2.1.2的股票最小:

这里MiniTest :: Spec继承自MiniTest :: Unit :: TestCase。 TestCase定义方法current并返回在initialize方法中设置的值。您可以在〜/ .rvm / rubies / ruby​​-2.1.2 / lib / ruby​​ / 2.1.0 / minitest / unit.rb的第1303行看到这一切:

def initialize name # :nodoc:
  @__name__ = name
  @__io__ = nil
  @passed = nil
  @@current = self # FIX: make thread local
end

def self.current # :nodoc:
  @@current # FIX: make thread local
end

因此,当您使用stock minitest继承测试类中的MiniTest :: Unit :: TestCase时,current被定义为一个方法,并保证在上面调用MiniTest :: Spec.current时返回一个值制作。这就是为什么它适用于红宝石2.1.2最小的股票。

最小的5.4.0

在5.4.0中,Minitest :: Spec继承自Minitest :: Test,它没有定义当前(也没有任何父节点)。当前方法直接在Minitest :: Spec上定义。它只返回Thread.current [:current_spec]:

# line 83 of ~/.rvm/gems/ruby-2.1.2/gems/minitest-5.4.0/lib/minitest/spec.rb      
def self.current # :nodoc:
  Thread.current[:current_spec]
end

Thread.current [:current_spec]的值在同一文件的第87行的Minitest :: Spec构造函数中设置:

def initialize name # :nodoc:
  super
  Thread.current[:current_spec] = self
end

问题是当你的测试类继承Minitest :: Test时,Minitest :: Spec构造函数永远不会被调用,并且Thread.current [:current_spec]永远不会被初始化。这意味着infect_an_assertion中对Minitest :: Spec.current的调用返回nil,这会导致在尝试在nil上调用assert_operator时看到的NoMethodError。解决方案是让您的测试类继承Minitest :: Spec,以便调用构造函数并且Thread.current [:current_spec]获取一个值。

以下是与minitest 5.4.0一起使用的原始代码的略微修改版本:

#!/usr/bin/env ruby

gem 'minitest'
require "minitest/autorun"

class TestUserKey < Minitest::Spec

  def test_simple
    data = 0
    assert( data >= 0 )
    data.must_be :>=,0
  end

end

希望这有帮助!

答案 1 :(得分:0)

minitest readme开始,似乎must样式语法是规范语法的一部分,这需要您使用describeit等方法定义自己的单元测试方法。