rspec+;水豚:功能测试每个测试只有一个期望?
我正在使用rspec和capybara为我的Rails 4应用程序编写一些功能测试。我让它正常工作,但我正在努力理解这种测试方式的某些方面 我一直在读,每个测试(它“应该…”块)应该只测试一件事。好的,听起来不错,但当我把它付诸实践时,我最终为简单的事情编写了大量的测试 比如说,我有一个标准的注册表单,它包含电子邮件、密码和信用卡 所以,为我的注册写一个功能测试,我需要写3个单独的测试来测试这个功能吗rspec+;水豚:功能测试每个测试只有一个期望?,rspec,tdd,capybara,integration-testing,Rspec,Tdd,Capybara,Integration Testing,我正在使用rspec和capybara为我的Rails 4应用程序编写一些功能测试。我让它正常工作,但我正在努力理解这种测试方式的某些方面 我一直在读,每个测试(它“应该…”块)应该只测试一件事。好的,听起来不错,但当我把它付诸实践时,我最终为简单的事情编写了大量的测试 比如说,我有一个标准的注册表单,它包含电子邮件、密码和信用卡 所以,为我的注册写一个功能测试,我需要写3个单独的测试来测试这个功能吗 describe "Signup" do it "informs user of an i
describe "Signup" do
it "informs user of an invalid email" do
visit signups_path
fill_in "Email", with: ""
click_button "Signup"
expect(page).to have_text("Email can't be blank")
end
it "informs user of an invalid password" do
visit signups_path
fill_in "Email", with: "test@test.com"
fill_in "Password", with: ""
click_button "Signup"
expect(page).to have_text("Password can't be blank")
end
it "informs user of an invalid credit card" do
visit signups_path
fill_in "Email", with: "test@test.com"
fill_in "Password", with: "valid-password"
fill_in "Card", with: "bogus"
click_button "Signup"
expect(page).to have_text("Card is invalid")
end
end
在一次测试中测试所有这些似乎更简单。我正在努力寻找合适的功能测试方法。我不想开始随机编写测试,这些测试(1)实际上没有覆盖/测试我的代码,或者(2)因为我写得不称职而变得臃肿和缓慢。我理解测试的必要性,只是不确定如何最好地进行上述功能测试。您应该使代码干涸,以尽量减少重复。您可以将在每个测试开始时调用的指令移动到之前的,并提取重复代码的帮助器方法:
describe "Signup" do
before do
visit signups_path
end
def fill_form(fields = {})
fields.each do |field_name, field_value|
fill_in field_name.to_s.capitalize, with: field_value
end
click_button "Signup"
end
it "informs user of an invalid email" do
fill_form email: ""
expect(page).to have_text("Email can't be blank")
end
it "informs user of an invalid password" do
fill_form email: "test@test.com", password: ""
expect(page).to have_text("Password can't be blank")
end
it "informs user of an invalid credit card" do
fill_form email: "test@test.com",
password: "valid-password",
card: "bogus"
expect(page).to have_text("Card is invalid")
end
end
编写集成测试时,重要的是要避免 下面是一个例子:
RSpec.feature'Signup',测试助手:[:Signup\u-ups]do
在{访问注册路径}之前
它会“通知用户一封无效的电子邮件”
注册。使用(电子邮件:'')注册
注册。应该。有错误(“电子邮件不能为空”)
结束
它会“通知用户密码无效”吗
注册。注册(电子邮件:'test@test.com')
注册应该有错误(“密码不能为空”)
结束
它“通知用户一张无效的信用卡”
注册。注册(电子邮件:'test@test.com,密码:“有效密码”,卡片:“伪造”)
注册错误('卡无效')
结束
结束
您可以使用以下工具或库实现:
classsignupstesthelper
这就是说,有时不需要完全隔离,并且结合这些场景应该会使测试套件大大加快:
RSpec.feature'Signup',测试助手:[:Signup\u-ups]do
在{访问注册路径}之前
它“通知用户无效信息”是否执行
注册。使用(电子邮件:'')注册
注册。应该。有错误(“电子邮件不能为空”)
注册。注册(电子邮件:'test@test.com')
注册应该有错误(“密码不能为空”)
注册。注册(电子邮件:'test@test.com,密码:“有效密码”,卡片:“伪造”)
注册错误('卡无效')
结束
结束
请注意,现在测试代码已经很好地封装,在压缩版本中仍然很容易遵循。为什么您觉得编写一个测试会更简单?@JustinKo,我认为这会更简单,因为对于每个测试,我都处于相同的“场景”,每个测试都有大量重复的代码。但是,经过一段时间的研究,我得出结论,在
块之前清除中的重复代码会有很大帮助,真正的测试应该只有1个expect/assert
,才能真正帮助解决钉点问题。我想我说的“更简单”是指“更短”。但有时短并不总是好的。经过一段时间的研究,这是解决这个问题最干净、最传统的方法。严格地说,为了真正成为一个单元测试,每个测试应该只期望/断言一件事情。这使得每个单独的测试更小,更容易维护。确实会导致运行测试套件的时间稍长,但这是一个折衷方案。我只遇到过一种情况,即我决定在一个测试中放入多个expect(…)
,这是因为我调用了一个外部API,进行多个调用的时间非常昂贵。