测试 做 Ajax 测试时遇到的问题

dothide · 2015年03月14日 · 最后由 dothide 回复于 2015年03月14日 · 2682 次阅读

在使用 Minitest 测试框架做测试时遇到一些问题,情况如下

个人比较习惯使用 spec 形式,并引入了 Capybara DSL

在写一个测试时,需要进行一个 click_link,而触发一个 ajax 请求,然后对返回的页面进行断言

测试是这样写的:

describe "节目页面跳转相关" do
    it "如果未登录,点击预约报名应该跳转至登录页面" do
      program = FactoryGirl.create(:program)
      # require_js
      visit programs_path
      click_link "appointment-program-#{program.id}", :href => "#"
      # wait_for_ajax
      page.must_have_selector 'h1', :text => 'Program Index'
    end
end

页面是这样写的:

<ul>
    <% @programs.each do |program| %>
      <li>
        <%= program.title %> <br>
        <%= link_to '报名', '#', 
          :id => "appointment-program-#{program.id}",
          :onclick => "programs_index.ajax_post_appoint(#{program.id})" %>
      </li>
    <% end %>
  </ul>

test_helper 是这样的

ENV["RAILS_ENV"] = "test"
require File.expand_path("../../config/environment", __FILE__)
require "rails/test_help"
require "minitest/rails"
require "minitest/rails/capybara"
require "minitest/reporters"

Minitest::Reporters.use!(
  Minitest::Reporters::ProgressReporter.new,
  ENV,
  Minitest.backtrace_filter
)

require 'database_cleaner'
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.clean_with(:truncation)

class ActiveSupport::TestCase
  ActiveRecord::Migration.check_pending!
  include FactoryGirl::Syntax::Methods
  Capybara.default_wait_time = 5

  def require_js
    Capybara.current_driver = :webkit
  end

  def wait_for_ajax
    Timeout.timeout(Capybara.default_wait_time) do
      active = page.evaluate_script('jQuery.active')
      until active == 0
        active = page.evaluate_script('jQuery.active')
      end
    end
  end

  def setup
    DatabaseCleaner.start
  end

  def teardown
    DatabaseCleaner.clean
    Capybara.reset_session!
    Capybara.use_default_driver
  end
end

class ActionDispatch::IntegrationTest
  include Capybara::DSL
  include Capybara::Assertions
end

问题

  1. 当我运行测试用例时,由于默认的 Capybara 驱动,所以 wait_for_ajax 它不认识,不能执行 JS 方法,因此我查文档后发现要在使用 JS 的地方切换成:webkit 驱动
  2. 当我放开测试用例中的 require_js 方法时,即使用 :webkit 驱动后,测试单元测试会变得龟速无比,一个测试要 16s(说好很快的呢)
  3. 而且更奇怪的是,此时 click_link 居然说没有找到该元素,也就是说界面上的 programs 是空数组,明明加了一条数据,这我也是醉了
  4. 由于第 3 条过不去,导致 wait_for_ajax 根本都执行不到

至此已经研究了好几个小时了,实在是束手无策

👏 总算解决了,主要是修改 test_helper.rb 文件,有几个关键点:

  • 不要启用 fixture,将 fixtures :all 删除
  • 在 AcitveSupport 类中,添加 self.use_transactional_fixtures = false
  • 不要在 ActiveSupport 类外面写 DatabaseCleaner 的设置语句
  • 更新 setup 方法 ruby def setup if metadata[:js] Capybara.current_driver = :webkit DatabaseCleaner.strategy = :truncation else DatabaseCleaner.strategy = :transaction DatabaseCleaner.start end end
  • 同时指定 Capybara 的 javascript_driver 为 :webkit ruby class ActionDispatch::IntegrationTest include Capybara::DSL include Capybara::Assertions Capybara.javascript_driver = :webkit end
  • 去除 minitest/reporters 似乎可以加快一点速度,现在单个用例的时间在 7-8s 左右了

Rails Test 本身是包在事务中的,每个 case 后回滚,不需要 DatabaseCleaner 吧?

#2 楼 @Rei 恩 每个 case 回滚是没有问题,但每个 case 之前会不会去清数据?我用了 webkit driver 后,就变得很奇怪,哪怕我在 case 中插入数据,通过模型能取到数据,但通过界面就是取不到了,我在怀疑是不是不同进程去操作的,我刚把数据插入,另一个进程就把数据都清了

需要 登录 后方可回复, 如果你还没有账号请 注册新账号