Ruby 问个 RSpec 的问题

feitian124 · 2012年07月16日 · 最后由 eclipse2008 回复于 2013年01月08日 · 5191 次阅读

问个 rspec 的问题,当我不用 rspec-expectation 时,它是怎么判断一个 case 是成功还是失败呢?

describe Object do
    it "how to determin this is fine or wrong?" do
        false
        #true
    end
end

false 或者 true 都是 pass 的。

没有 assert

assert false

没有 rspec-expectation,自然都是成功的。

@leomayleomay @heliang7 我这里ruby 1.8.6assert, 不是core里的吗 ? 我就是想知道it方法是如何判断成功和失败的,现在能肯定不是基于return value. 那是异常?或者assert(居然在ruby中不是关键字)?或者其他什么东西。

true.should be_false

@hisea 谢谢,你这种写法是对的。能再帮忙解答下我 3 楼的问题吗,水平有限,到翻 rspec 的源码,没找到答案。

describe Object do
  it "how to determin this is fine or wrong" do
    true.should be_true
  end
  it "{} works?" { true.should be_true }
end

我一开始以为describeit是某个类或模块提供的方法,通过继承或者mixin所以上面代码能工作了。但后面想想,不对呀,仅上面这段代码,不需要require或者include什么东西,它也能工作的好好的。

那么上面这段代码,应该是类似于rspec的配置文件,rspec 会读取它并解释它(你们说的 DSL?),或者有个类似于eval的动态执行的东西,总之暂时还不懂。

撇下这些不管,我现在很奇怪,那个rspec是怎样根据do .. end块中的内容,来判断一个 testcase 是真还是假呢?

现在肯定不是靠返回值,因为如果ture.should be_true返回值是true的话,和我直接写true结果应该一样,但是我直接写false它还是成功;

assert又不是ruby关键字,也不像;

那是通过抛异常?那个啥shoud,还有be_ture,是个啥子东西嘛!

你说对了,rspec 是一个 DSL.

assert 不是 rspec 里面的,xUnit 之类的会有 assert. Ruby 的话是 Test::Unit

不过道理都是一样的。

测试里面其实测试并不是返回 true 或者 false 的。

测试比简单的 true 和 false 更复杂一些。

同一个测试可以因为不同的原因 fail。 expectation 就是这个样子的,在一个测试里面 expect 或者说‘期待’一个或者多个东西是成立的。

it "how to determin this is fine or wrong" do
  true.should be_true
  2.should == 3
end

be_true 和 ==3 是 matcher,就是具体来检验你期待的东西成不成立的 rspec 有很多https://github.com/rspec/rspec-expectations/tree/master/lib/rspec/matchers/built_in

大部分都是 ruby 语言的 matcher.

shoulda 是一个 gem,提供了 rails 的 matcher,比如

describe Post do
  it { should belong_to(:user) }
  it { should validate_presence_of(:title) }
end

it 是 dsl 的一部分,其目的是让 test 看起来像一个说明或者是规范,或者说是 specification,这就是 rspec 名称的由来。

it 其实是一个方法。用来定义一个 example

example 可以想象成一个 testcase,不过稍微复杂些的是有些 context 的东西。 具体定义在这里https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/example_group.rb

其中最关键的一行是这个 examples << RSpec::Core::Example.new(self, desc, options, block)

吧 block 也就是你的 true.should be_true 传到一个新的 example 里面去了。

其他的 should, describe 等等,都是方法,rspec 是元编程的超级合身。从上面的源码就能看出,跟 it 不同名的功能几乎一样的方法有很多

# Defines an example within a group.
     define_example_method :example
     # Defines an example within a group.
     #
     # @see example
     define_example_method :it
     # Defines an example within a group.
     # This is here primarily for backward compatibility with early versions
     # of RSpec which used `context` and `specify` instead of `describe` and
     # `it`.
     define_example_method :specify

     # Shortcut to define an example with `:focus` => true
     define_example_method :focus,   :focused => true, :focus => true
     # Shortcut to define an example with `:focus` => true
     define_example_method :focused, :focused => true, :focus => true

     # Shortcut to define an example with :pending => true
     define_example_method :pending,  :pending => true
     # Shortcut to define an example with :pending => 'Temporarily disabled with xexample'
     define_example_method :xexample, :pending => 'Temporarily disabled with xexample'
     # Shortcut to define an example with :pending => 'Temporarily disabled with xit'
     define_example_method :xit,      :pending => 'Temporarily disabled with xit'
     # Shortcut to define an example with :pending => 'Temporarily disabled with xspecify'
     define_example_method :xspecify, :pending => 'Temporarily disabled with xspecify'

楼主应该是不明白 should 是怎么工作的吧。 其实很简单,should 就是个 mixin 进去的 method,在里面计算 self 的值是否符合 expectatin,如果不符合就告诉测试环境(总有方法让它获得环境的)——“这里有一个 assertion 失败”,基本原理就是这样

@hisea 非常感谢。学到很多。 我混淆了rspec和rspec-core。我以为should之类的东西,应该是rspec-expectation里面的,那我写最简单的case,应该只用到了rspec-core,没用到rspec-expectation,所以纠结should是哪里来的。 上次去shanghai ruby Tuesday,弄混了rake和rack,今天又弄混一个,尴尬。 打算好好研究下rake,bundle,rspec这些小而精的工具的源码。再次感谢。

10 楼 已删除
需要 登录 后方可回复, 如果你还没有账号请 注册新账号