该文章同步发布於:我的部落格
昨天我们做了一个关於汉堡种类的测试,但真正的测试怎麽可能这麽少呢!
所以我们今天要更进一步的来把它变得稍微复杂一点,并且让他看起来更乾净,更好一些!
RSpec.describe Burger do
it "has a type" do
burger = Burger.new('Big mac')
expect(burger.type).to eq('Big mac')
end
end
还记得我们两天才撰写测试的时候,describe
後面加入的是 "Burger"
字串,但我们现在可以改用常数,也就是我们测试类别的名称。
只是少了两个括号有什麽差别吗?当然有,他的好处可以让我们少写很多的程序码,我们後面会提到直接使用 常数 到底有哪些优势!(关键字:subject
)
我们现在的测试只有单单测试一个汉堡的种类,但我们现在要让他更复杂一些。
我们想要让汉堡可以有肉类和起司的选项,我们要把大麦克给拆开来看看!
以下为逐步图,从原本的作法一步一步拆开来!
# 原本的状况
RSpec.describe Burger do
it "has a type" do
burger = Burger.new('Big mac')
expect(burger.type).to eq('Big mac')
end
end
这边我们希望汉堡可以放入两种种类,分别是牛肉、以及切达起司!
我们一样保持先把测试给完成再去改你的程序码,渐渐地习惯这种流程,不要急着去改,这样就丧失了 TDD 的意义了!
# 第一步
RSpec.describe Burger do
it "has a type" do
burger = Burger.new('Beef', 'Cheddar')
expect(burger.type).to eq('Big mac')
end
end
下面的写法看起来非常合理,但却有些瑕疵。
在 RSpec 里面我们会希望测试可以越乾净越好,一个 example
尽量只有一个 expectation
这样会让我们可以把功能切的更细、考虑到更多,尤其在 Output 也会完全不一样!
而且这边的叙述也不够精确, has a type
但却没有说是什麽样的类型,当测试的数量不断地增加的时候,这就会造成你在看错误讯息时更大的负担!
# 第二步
RSpec.describe Burger do
it "has a type" do
burger = Burger.new('Beef', 'Cheddar')
expect(burger.meat).to eq('Beef')
expect(burger.cheese).to eq('Cheddar')
end
end
下面是我们把 expectation
拆成两个 example
的样子!
也把两个 example
的叙述变得更仔细,让人可以一目了然这个测试的目的是什麽!
有没有觉得画面变得更清楚啦?虽然我们的例子都很短,你可能觉得放一起也没关系,但养成好习惯会让以後事半功倍喔!
# 第三步
RSpec.describe Burger do
it "has cheese" do
burger = Burger.new('Beef', 'Cheddar')
expect(burger.cheese).to eq('Cheddar')
end
it "has meat" do
burger = Burger.new('Beef', 'Cheddar')
expect(burger.meat).to eq('Beef')
end
end
好的,现在我们的测试已经根据新的需求有了改变,想当然我们输入测试的指令一定不会通过的。
接着又来到 TDD 的第二个步骤了,我们要让这个测试 PASS !
输入了 rspec spec/burger_spec.rb
後
我们再来阅读这个错误的问题在哪,错误的地方在於类别的 initialize
方法这边。
错误的问题则是下方的 ArgumentError
可以看到他写到只期待一个参数,但我们却给了两个参数。
好的没问题,我们来到 burger.rb
存放类别的档案,稍作修改一下!
class Burger
attr_accessor :type
def initialize(meat, cheese)
@type = type
end
end
我们给了他两个参数了,接着我们在输入 rspec spec/burger.rb
来看看错误的讯息是什麽?
喔!这次发生错误的地方在测试的档案中,原因是我们的 Burger
没有 meat
这个方法,昨天的也有提到这样的问题该如何解决!简简单单~
给他两个方法让他可以读取就好啦~
class Burger
attr_accessor :meat, :cheese
def initialize(meat, cheese)
@type = type
end
end
肯定会通过的吧?
啊...太大意了,我们应该要注意到实体变数的问题,目前这个物件里面没有存放肉和起司的变数,快加给他!
class Burger
attr_accessor :meat, :cheese
def initialize(meat, cheese)
@meat = meat
@cheese = cheese
end
end
恭喜啊!我们又通过了一次测试了!
记得我刚刚前面有提到 example
不要重复测试的重要性吗?
看看这边的 Output 就很明显像是作文一样,告诉我们汉堡有肉有起司,但若是你全部都写在一个 example
里面,就会变得不清不楚了~
一个
it
代表的是一个example
喔,这会关系到测试的可读性!所以不是越省越好喔~
记得今天的开头,我有提到先把 describe
後面的字串描述改成类别的常数吧?
仔细看看,今天我们的测试码就有两行是一模一样的重复代码,TDD 的第三步就是要重构程序码以及测试代码!
明天我将会介绍整理 RSpec 的方式,有许多的小帮手能够让我们的测试码更简洁,更易读!
<<: Day 0xC - Debug 地狱第三天,终於逃脱了 (建立订单)
>>: Day 22 - Follow Along Links
因应疫情,全部都是视讯线上面试, 这边收集一些点,以便未来提醒自己。 面试当天要测试硬体(镜头、麦克...
哈罗 想请教一下各位 目前公司开一家新店 我们用了Ruckus R320的AP 因为是跨县分店 我们...
在 SMTP Mail 之後,今天要跟大家介绍第二种通知方式 Custom alertscripts...
我们来看看Executor介面的内容: package java.util.concurrent; ...
一、前言 classnames 是一个方便 JavaScript 管理 class name 的...