该文章同步发布於:我的部落格
昨天的文章介绍了 TDD 的流程和精神等等。
今天我们要正式进入 RSpec 的世界,所以我们从最一开始容易见到的几种语法开始做解释和教学!
假设我们今天要开一间汉堡店,那我们就要来想像汉堡店的测试!
首先我们在 Spec 档案里面加入一个 burger_spec.rb
的档案!
这样我们就可以开始来写啦~
Rspec.describe 'Burger' do
...
end
这个 describe
呢,主要在解释我们要测试的主要目标是什麽?( 这边是测试汉堡这个类别 ),而这边也有一个 Ruby 小小的惯例,就是可以省略 ( ) 小括号,所以原本应该是这样...
RSpec.describe('Burger') do
...
end
所以从这边我们可以了解到,describe
应该是 RSpec 的类别方法唷!
接着 describe
也同时要接收一个 Ruby 的 block 用 do..end
的方式接在後面。
写到这边,我们已经完成了一个 example group
,直翻的话叫做:例子的集合???
也就是我们提供了一个 example
的地基,在这里面可以放入许多的小 example
,在 RSpec 的世界中,每一个我们所期待的事件都是一个 example
,而 describe
在做的事情就组织着这些小东西!
上面的例子中,我们建立了一个 example group
而在这个介绍的语法里,我们要建立单一个测试,也就是一个小的 example
。
回到上面的例子,我们继续写下去,我们想了一下,希望汉堡要有种类,就用坊间常见的汉堡来做例子就可以了!
RSpec.describe 'Burger' do
it 'has a type' do
...
end
end
可以看到我们写了一个 it
这也是一种方法,只能存活在 example group
里面,而後面会接一段字串来描述这个测试的目的是什麽?然後再接一个 block。
这个 it
方法最大的价值就在於,他能够让一个测试变得易读,然後清楚的描述这个行为是什麽。
而不是在描述的地方写到你是如何做到的,不需要写我是用 Array 来存放,或用 Hash 做 map,诸如此类的东西,不需要被特别的提出来!只需要专注在这个测试的行为是什麽?什麽样的行为?
像我们刚刚写的就很明确,一个汉堡他应该要有种类,非常的易读!
这主要是 it
这个方法的目的,描述一个测试的行为,不是结果喔!结果会有另一个方法来执行,但这边的目的在於 描述物件的行为
接着继续来开发我们的汉堡店,还记得开发的需求是说 汉堡需要有不同的种类,就着我们就来想像一下,我们需要做出汉堡的实体,然後给予他种类,并通过测试。
上述也算是一个 TDD 的回圈喔!还记得吗?现在我们在根据需求并使其通过测试!
RSpec.describe 'Burger' do
it 'has a typy' do
burger = Burger.new('Big mac')
...
end
end
我们在这边建立了一个 burger
的实体,便给予他种类的名称Big mac
,接着我们需要测试它,所以我们会用到一个叫做 expect
的方法。
expect
这个方法接收的参数是我们要测试的对象,也就是我们刚刚做出来的 burger
。
那要记得我们这次测试的目的是,希望他有一个种类,所以我们在 expect
的後方写的是 burger.type
并希望得到我们要的答案!
RSpec.describe 'Burger' do
it 'has a typy' do
burger = Burger.new('Big mac')
expect(burger.type)....
end
end
接着我们继续的写下去:
RSpec.describe 'Burger' do
it 'has a typy' do
burger = Burger.new('Big mac')
expect(burger.type).to eq('Big mac')
end
end
我们专注在第四行上面,如果用我破烂的英文来翻译的话,会是
期待汉堡的种类等於
Big mac
这样应该是还蛮容易阅读的,虽然不是文法很精确的英文,但我觉得看得很舒服!
我们重新的整理一下我们写了一些什麽,以及他们有什麽用途。
首先是 expect
,他是一个 RSpec 提供的方法,可以接受物件、物件的属性、方法、甚至是基本的 Ruby 运算式,而这个 expect
方法会针对你传入的参数进行运算,并且回传一个物件。
#<RSpec::Expectations::ExpectationTarget:0x00007fb81f240278 @target="Big mac">
若是把 expect(burger.type)
印出来就会长的像上面一样,是一个物件的概念,以及具备 @target
这个实体变数 ( @target 会是我们主要接受测试的项目喔! )
而这个物件会拥有 to
这个实体方法,这个 to
方法呢,需要接受一个叫做 matcher
的物件,那这个物件是怎麽产生的?
就在於後面我们写入的 eq('Big mac')
这个方法也会产生一个物件
#<RSpec::Matchers::BuiltIn::Eq:0x00007fdb92afa3f0 @expected="Big mac">
具有一个 @expected
的实体变数!
而 to
这个方法呢,简单的来说就是比对这两个物件的实体变数,回传成功或是失败,当然实际上更复杂一点,有针对许多的情况来做 raise error 但基本逻辑就是这样进行的,所以若是你没有传入 matcher
这个例子就没有办法完成!
OK,所以到这边我们已经写完了一个最基本的测试了!接着我们对着终端机输入 rspec spec/burger_spec.rb
会看到~
竟然没有通过...但相信看过昨天的文章就能够知道错误是在哪里发生的,而明天开始将会一步一步地读懂错误的讯息并且使其通过测试~毕竟看懂错误讯息也是工程师很重要的一项技能喔!
今天我们学会了整个 RSpec 的主架构,从利用 describe
框出一个区块让我们写小 example
再到使用 it
来叙述我们测试的行为,以及利用 expect
&eq
来进行比对测试!
这样可以算是一个 unit test 罗!运用这几个方法,相信很简单的测试也难不倒你了,但可惜的是我们最後遇到了错误讯息,但没关系!我们明天来解决它。
昨天我们做完前置作业了,今天我们来看一下这个 HTML Service 是怎麽用! 简单来说,就是可...
昨天我们档案上传功能有个问题是不能上传太大的档案,根据我的研究发现,写入档案的部分所需要的时间是不一...
-网站WentzWu.com的X.509证书样本 因为如今在实践中很少使用正斜杠“ /”作为分隔符...
在完成登入功能之前,我想要先介绍一下Angular的路由系统 Angular Routing: In...
▉A.17 Information Security Aspects Of Business营运持续...