我正在使用rspec和capybara为我的Rails 4应用程序编写一些功能测试。我的工作正常,但是我很难理解这种测试方式的某些方面。
我一直在读,每个测试(“应该...”块)应该只测试1个项目。好的,听起来不错,但是当我付诸实践时,我最终为简单的事情写了很多测试。
假设我有一个标准的注册表格,其中包含电子邮件,密码和信用卡。
因此,test为我的注册编写了功能测试,是否需要编写3个单独的测试来测试功能?
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)由于我编写的能力不佳而变得肿且缓慢。我了解测试的必要性,只是不确定如何最好地进行上述功能测试。
你应该干燥代码以最大程度地减少重复。你可以将每次测试开始时调用的指令移动到before
,并为重复的代码提取帮助方法:
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
经过一段时间的研究,这是解决此问题的最干净,最常规的方法。严格来说,每个测试只应该期望/声明1件东西才能真正成为单元测试。这样可以使每个单独的测试变得更小且更易于维护。确实需要更长的时间来运行测试套件,但这是一个折衷方案。我只遇到过一种情况,我决定
expect(...)
在一个测试中进行多次测试,这是因为我正在调用一个外部API,并且进行多次调用非常耗时。