我一直在使用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?如果是这样,有人可以解释原因吗?
答案 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
样式语法是规范语法的一部分,这需要您使用describe
和it
等方法定义自己的单元测试方法。