rspec + capybara:每次测试只测试1个特征?

时间:2014-03-01 23:45:17

标签: rspec tdd capybara integration-testing

我正在使用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)变得臃肿和缓慢,因为我无能为力地编写它们。我理解测试的必要性,只是不确定如何最好地进行如上所述的功能测试。

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 objectsCapybara 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

请注意,由于测试代码已经很好地封装,因此在简化版本中仍然很容易遵循。