我正在使用rspec和capybara为我的Rails 4应用编写一些功能测试。我让它正常工作,但我正在努力理解这种测试的某些方面。
我一直在读,每个测试(它应该......)块只能测试一件事。好吧,这听起来很棒,但是当我把它付诸实践时,我最终会为简单的事情编写大量的测试。
假设我有一个标准的注册表单,可以使用电子邮件,密码和信用卡。
所以测试为我的注册编写功能测试,我是否必须编写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)变得臃肿和缓慢,因为我无能为力地编写它们。我理解测试的必要性,只是不确定如何最好地进行如上所述的功能测试。
答案 0 :(得分:1)
您应该干掉代码以尽量减少重复。您可以将在每次测试开始时调用的指令移动到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 :(得分:0)
编写集成测试时,请务必避免使用coupling the test to the UI。
这是一个例子:
switch (number) {
#pragma warning disable format // @formatter:off
case 1: cardinal = "one"; animal = "monkey"; break;
case 2: cardinal = "two"; animal = "horse"; break;
case 3: cardinal = "three"; animal = "pig"; break;
case 4: cardinal = "four"; animal = "chicken"; break;
#pragma warning restore format // @formatter:on
}
您可以使用page objects或Capybara Test Helpers之类的库来实现:
RSpec.feature 'Signup', test_helpers: [:sign_ups] do
before { visit signups_path }
it 'informs user of an invalid email' do
sign_ups.sign_up_with(email: '')
sign_ups.should.have_error("Email can't be blank")
end
it 'informs user of an invalid password' do
sign_ups.sign_up_with(email: 'test@test.com')
sign_ups.should.have_error("Password can't be blank")
end
it 'informs user of an invalid credit card' do
sign_ups.sign_up_with(email: 'test@test.com', password: 'valid-password', card: 'bogus')
sign_ups.should.have_error('Card is invalid')
end
end
也就是说,有时不需要完全隔离,并且组合方案可以使测试套件明显更快:
class SignUpsTestHelper < Capybara::TestHelper
def sign_up_with(email:, password: nil, card: nil)
fill_in 'Email', with: email
fill_in 'Password', with: password if password
fill_in 'Card', with: card if card
click_button 'Signup'
end
def have_error(message)
have_selector('#error_explanation', text: message)
end
end
请注意,由于测试代码已经很好地封装,因此在简化版本中仍然很容易遵循。