该文章同步发布於:我的部落格
之前有介绍过 before hooks
的使用方法,今天也可以介绍一下 after hooks
的使用方法,我们先用范例来看看!
RSpec.describe "before and after hooks" do
before(:example) do
p "before hooks"
end
after(:example) do
p "after hooks"
end
it "test for before & after" do
p "inner example"
expect(1 + 1).to eq(2)
end
end
下面这是 Output 的结果,可以看到执行顺序的不同!
那一定会很好奇,什麽时候要使用 after hooks
,有时候我们为了效能考虑,某些工程师会不想要每次都产生一个新的物件。
所以会在 after hooks
中把物件 Reset 资料或是清空资料库等等的动作,都会在这时候使用!
可以用一个简单的范例来看看~
RSpec.describe "before and after hooks" do
before(:example) do
end
after(:example) do
p @array
p @array.clear
end
it "test for before & after" do
@array = []
p "Inner #{@array}"
@array << '1'
expect(1 + 1).to eq(2)
end
end
我们在测试中产生一个 @array
然後在 after hooks
中清空它,下面是 Out put 的样子!
可以看到 @array
在结束後被清除了,这对於某些情况是有帮助的,但使用的程度并没有到极高的情形,还是可以把它记起来,说不定哪天会派上用场喔!
但我自己还是比较喜欢在每个例子前产生物件,最後还是取决於你们团队的决定和方向~
刚刚介绍完 after hooks
的运作模式,我要介绍一下传入的参数所造成的差别!
我们一般都是预设在 (:each)
的情形,也就是你每一个 example
都跑一次的意思!
这边介绍一个 (:context)
的选项,可以让你在 describe
& context
的前後执行 hooks,我们来看看例子吧!
RSpec.describe "before and after hooks" do
before(:context) do
p "before context"
end
before(:example) do
p "before example"
end
after(:example) do
p "after example"
end
after(:context) do
p "after context"
end
it "test for before & after" do
expect(1 + 1).to eq(2)
end
end
接着看 OutPut 会非常明显和清楚!
(:context)
会在整个测试最开始的时候执行一次,然後会在整个测试结束的时候执行!
这个的用处在於,某些设定你只需要一次,就可以在每个测试里面拿到,而不需要每一个 example 都产生一次,这样就会有效能上很大的差别。
所以写测试的时候,稍微考虑一下是不是都会被使用到而且又不会被改变,如果答案是确定的!那就可以使用 (:context)
的选项来帮助你喔!
熟悉的两个 hooks 的运作模式之後,我们要来把 hooks 加入箝套里面测试一下自己是不是真的理解了?
所以我们先上程序码( 可以自己先想一下答案! )
RSpec.describe "before and after hooks" do
before(:context) do
p "OUTER Before context"
end
before(:example) do
p "OUTER Before example"
end
it "will pass" do
expect(1 + 1).to eq(2)
end
context "when it can pass" do
before(:context) do
p "INNER Before context"
end
before(:example) do
p "INNER Before example"
end
it "will pass too" do
expect(2 + 2).to eq(4)
end
end
end
有办法一步步的推敲出正确答案的话,代表已经完全理解了 hooks 的运作顺序了。
我们要去思考测试码是由上至下的读取,所以会先经过什麽?遇到什麽又会触发什麽?
只要能一步一步地厘清其实就不会感觉非常复杂~
公布答案:
我猜最容易没想到的地方就是在 context 里面的 example 也吃到了外面的 before hooks 吧!
最外层的物件,在里面也是拿得到的,这对於一开始写 RSpec 的人还蛮有帮助的。
因为在一边整理程序码的时候,会出现这个物件会不会拿不到,要不要再写一个 let
等等的疑问~
那至於为什麽要在不同的地方写 hooks 呢?
是因为某些 Context 可能有属於他的物件需要放在里面,若是所有的东西都放在最外层,很有可能不小心就命到相同的名字,或是看起来很杂乱!
虽说写在最外面肯定是不会有什麽问题,但能够精准的物件放在他的作用域,也是一个工程师厉不厉害的指标喔!
刚刚提到了内层可以取得外层的物件,但如果我想要在 context 里面测试同一个物件,不同的行为怎麽做呢?
我们先用个范例来看看:
class Burger
attr_accessor :type
def initialize(type = "small")
@type = type
end
end
RSpec.describe Burger do
let(:burger) { Burger.new("Big") }
it "type will be Big" do
expect(burger.type).to eq("Big")
end
context "when we didn't give argument" do
let(:burger) { Burger.new } # 利用覆写来通过测试
it "typ will be small" do
expect(burger.type).to eq("small")
end
end
end
当我们想要给一个 context 的情境来测试没有传入参数的预设值时,要如何可以通过测试?
我们可以利用覆写 burger 这个物件的内容,来通过测试。
当测试码跑到第 18 行时,他会从自己的作用域开始找寻一个叫做 burger 的物件,若是没有就会往上去找!
所以不覆写的话,会找到第 9 行的 burger 物件!就会没办法通过测试。
所以当我们理解了作用域,就可以随心所欲的撰写测试,根据不同的情境加入不同的条件!
而且使用 let
也不担心效能的问题,还记得我们在介绍 let
的时候提过的 lazy-loading 吗? 超赞的!
今天介绍了 RSpec 的作用域,以及覆写带来的帮助,希望可以帮到像我一样的新手。
毕竟测试也不是超基本的知识,还是需要自己去读文件和练习 KATA 才会进步!
所以希望自己的想法可以有所帮助~
明天会介绍 subject
这个物件,也会介绍缩短程序码的小方法!( Ruby 生态圈就是越简洁优雅越好 )
又饶舌了 适用人员: 技术人员。 适用法规: 资通安全责任等级分级办法 技术面分类提要 网路架构 端...
大部分的人下载 App 都是直接在 App Store 或 Google Play 搜寻 ASO 就...
SEO优化-内部连结和外部反向连结 所谓的连结通常是使用文字、图片或是网址作为超连结,SEO优化中常...
总算写到 30 天了,谢谢各位看倌的耐心, 最後一篇是今年铁人赛的总回顾,我想对自己一开始的规划是否...
这个系列是制作讯号灯,制作出一些简单的讯号灯,当作我们判断的依据。这些灯号之後还可以做出更为精细的比...