原文链接:https://www.rubyguides.com/2018/07/rspec-tutorial/
你想学习如何使用RSpec为Ruby应用程序编写测试用例吗?
那你来对地方了!
在本教程中,我将想你展示如何去做。
一、为什么要编写测试用例?
它建立了一个防止错误的安全网,如果你没有完善的测试系统,你不敢轻易修改代码,因为可能会破坏一些东西;
它会提升你的自信心;
它能帮助你记录代码,你的测试描述了程序功能;
它可以给你反馈,它可以确保代码产生预期的结果。
如果你想写一些复杂的逻辑,你需要确保它可以用于许多不同的输入,而不仅仅是您想出的一个示例。
二、RSpec 入门
步骤1:初始化
require 'rspec/autorun'
#create a describe block to group all your tests together & to tell RSpec which class you are testing.
describe Factorial do
# ...
end
步骤2:it block
describe Factorial do
it "does something" do
# ...
end
end
三、RSpec测试示例
describe Factorial do
it "finds the factorial of 5" do
calculator = Factorial.new
expect(calculator.factorial_of(5)).to eq(120)
end
end
当您运行此代码时,您将获得以下信息:
uninitialized constant Factorial (NameError)
这是正常的,因为我们还没有 Factorial
类,创建一个
class Factorial
end
然后又提示
undefined method 'factorial_of'
同样的创建method factorial_of
class Factorial
def factorial_of
end
end
再运行
wrong number of arguments (given 1, expected 0)
不用害怕错误出现,它们是反馈,最终通向正确的道理。
向factorial_of方法传参数
class Factorial
def factorial_of(n)
end
end
运行后你会发现测试失败
expected: 120
got: nil
接下来实现这个方法
class Factorial
def factorial_of(n)
(1..n).inject(:*)
end
end
你将获得第一个通过的测试用例
.
Finished in 0.00315 seconds (files took 0.09083 seconds to load)
1 example, 0 failures
您首先编写测试用例,然后让测试指导您下一步需要做什么。
四、RSpec Let 方法
如果要编写很多测试用例,并且重复使用相同的对象,你可以用let语句定义他们
例如
describe Factorial do
let(:calculator) { Factorial.new }
it "finds the factorial of 5" do
expect(calculator.factorial_of(5)).to eq(120)
end
end
现在你可以在同一describe块下的所有测试方法中使用calculator
但是你要知道的是,在你第一次使用该对象之前,let 不会创建它,这个可能会带来一些副作用,比如创建数据库实例,或者写入文件。
最好能避免这些副作用,但是如果你做不到,那请使用let! 方法。
let!(:user) { User.create("rspec@rubyguides.com") }
let!方法不是懒加载的,所以对象会在运行前被创建
五、如何使用Subject Method
let的另一个版本是subject,唯一不同的是,只能拥有一个主题,它是要测试的主要对象的实例。
RSpec已经创建了一个默认主题,如下所示:
subject { Factorial.new }
这个被称为 “implicit subject”
你可以像这样使用它:
describe Factorial do
it "finds the factorial of 5" do
expect(subject.factorial_of(5)).to eq(120)
end
end
您可以给主题起一个名字:
subject(:calculator) { Factorial.new }
六、如何在所有测试之前运行代码
RSpec具有执行挂钩,可以使用它在每次测试或整个测试组之前和之后运行某些东西。
describe Shop do
before(:all) { Shop.prepare_database }
after (:all) { Shop.cleanup_database }
end
如果要为每个测试用例运行此代码,则可以使用:each代替:all。
七、如何创建测试子组
如果要在应用中测试不同的场景,则将相关测试组合在一起可能会有所帮助。
使用RSpec中的context block来执行此操作。
describe Course do
context "when user is logged in" do
it "displays the course lessons" do
end
it "displays the course description" do
end
end
context "when user it NOT logged in" do
it "redirects to login page" do
end
it "it shows a message" do
end
end
end
八、RSpec Expectations & Matchers
你可能还记得这个例子
expect(calculator.factorial_of(5)).to eq(120)
eq 就是 matcher的一种,还有一些其他的匹配器
例如 be_something
expect(nil).to be_nil
- include (for arrays & hashes)
- start_with
- end_with
- match (for regular expression matching)
- be_between
- have_key / have_value (for hashes)
- be_instance_of
- respond_to
- have_attributes (for testing instance variables)
这些文章可以参考