如何将Capybara Rails TestCase作为单个事务运行?

时间:2014-11-11 12:43:24

标签: ruby-on-rails ruby-on-rails-4 capybara minitest

我有一个包含博客功能的rails应用。

在一个单一的功能测试中(使用Capybara :: Rails :: TestCase,对于博客使用ruby测试(断言/反驳),即不是规范),我想测试添加帖子,添加评论,编辑帖子,作为单独的测试 - 每个测试都建立在最后一个测试的基础上,因为第一个测试中创建的帖子在第二个测试中被评论,依此类推。

我看过哪些帖子显示了在单元测试中执行此操作的解决方法(全局变量,使用setup / teardown),但我想知道是否有更直接的方法在功能测试中执行此操作,因为它可能更多在这里很常见。

理想情况下,我希望登录会话保持不变,以及在先前测试中创建的数据库记录在TestCase中的每个测试中保持不变。设置和拆解可以用于每次登录,但不能用于为帖子,评论等创建的中间记录。

我想要类似的东西:

class BlogTest< Capybara::Rails::TestCase
  test 'can sign in' do
      user = User.create!(name: "user", 
             email: "user@example.com", 
             password: "passw0rd!", password_confirmation: "passw0rd!")

      visit new_user_session_path
      fill_in('Login', :with => user.email)
      fill_in('Password', :with => user.password)
      check('Remember me')
      click_button('Sign in')
  end

  test 'can create post' do
    visit new_post_path # how can I have user logged in?
    fill_in "Title", with: "My first post title!"
    fill_in "Body", with: "My first post body!"
    click_button "Publish"
  end

  test 'can comment on post' do
    visit post_path(Post.first) # should go to post created in last test
    click_button "Add comment"
    ...
  end
end

我听说这可能在Cucumber中有用,但是出于其他原因选择不使用Cucumber,所以希望它与Minitest和Capybara合作。

1 个答案:

答案 0 :(得分:1)

Capybara::Rails::TestCase继承自ActiveSupport::TestCaseActiveSupport::TestCase的主要功能之一是它在数据库事务中运行每个测试。有办法解决这个问题,但我不推荐它们。

相反,我建议您使用rails测试类的行为。在这种情况下,您希望在测试之间共享操作。我建议您将这些操作提取到方法中,并在测试中调用这些方法。以下是我将如何使用您的测试代码实现此功能:

class BlogTest< Capybara::Rails::TestCase
  def user
    @user ||= User.create!(name: "user", 
                           email: "user@example.com",
                           password: user_password,
                           password_confirmation: user_password)
  end

  def user_password
    "passw0rd!"
  end

  def sign_in(email, password)
    visit new_user_session_path
    fill_in('Login', :with => email)
    fill_in('Password', :with => password)
    check('Remember me')
    click_button('Sign in')
  end

  def create_post(title = "My first post title!",
                  body = "My first post body!")
    visit new_post_path # how can I have user logged in?
    fill_in "Title", with: title
    fill_in "Body", with: body
    click_button "Publish"
  end

  def comment_on_post(post, comment)
    visit post_path(post)
    click_button "Add comment"
    # ...
  end

  test "can sign in" do
    sign_in(user.email, user_password)
    # add assertions here that you are signed in correctly
  end

  test "can't sign in with a bad password" do
    sign_in(user.email, "Not the real password")
    # add assertions here that you are not signed in
  end

  test "can create post when signed in" do
    sign_in(user.email, user_password)
    create_post
    # add assertions here that post was created correctly
  end

  test "can't create post when not signed in" do
    create_post
    # add assertions here that post was not created
  end

  test "can comment on post when signed in" do
    sign_in(user.email, user_password)
    create_post
    post = user.posts.order(:created_at).last
    comment_on_post(post, "I can comment because I'm signed in!")
    # add assertions here that comment was created correctly
  end

  test "can't comment on post when not signed in" do
    post = Post.first
    comment_on_post(post, "I can't comment because I'm not signed in!")
    # add assertions here that comment was not created
  end
end

每个操作都有一个好名字,您可以将这些操作重用于不同类型的测试。每个测试都在数据库事务中执行,因此每次运行每个测试方法时,数据库看起来都是一样的。