Rails + Capybara-webkit - javascript代码覆盖率?

时间:2012-12-23 00:16:58

标签: ruby-on-rails testing rcov jscoverage

我正在研究使用capybara-webkit对应用程序进行一些接近真实的测试。这是绝对必要的,因为该应用程序具有非常丰富的基于JS的UI,而Rails部分主要是API调用。

问题是:是否有任何工具可以集成到测试管道中,可以检测Javascript代码并报告其覆盖范围?这里的关键是能够轻松地集成到测试工作流程中(就像rcov / simplecov一样) - 我不喜欢这个想法用jscoverage或analogue自己做:)

非常感谢提前。

2 个答案:

答案 0 :(得分:1)

更新:从JSCover版本1.05开始,不再需要我在上一个答案中概述的黑客攻击。我已经更新了我的答案以反映这一点。

我设法让JSCover在Rails + Capybara管道中工作,但确实需要一些黑客才能让它工作。我建立了一个小的rake任务:

  1. 使用rails资产管道生成脚本
  2. 调用java jar来检测所有文件,并在temp dir中生成一个空报告
  3. 修补jscover.js脚本以“报告模式”运行(最后添加jscoverage_isReport = true)
  4. 将结果复制到/ public / assets,以便测试在不需要任何更改的情况下进行检索,因此可以在浏览器中自动打开覆盖率报告
  5. 然后我添加了一个设置任务,以便在测试开始时清除浏览器的localStorage,并在最后写出完成报告的拆卸任务。

    def setup
      unless $startup_once
        $startup_once=true
        puts 'Clearing localStorage'
        visit('/')
        page.execute_script('localStorage.removeItem("jscover");')
      end
    end
    def teardown
      out=page.evaluate_script("typeof(_$jscoverage)!='undefined' && jscoverage_serializeCoverageToJSON()")
      unless out.blank? then
        File.open(File.join(Rails.root,"public/assets/jscoverage.json"), 'w') {|f| f.write(out) }
      end
    end
    

    无论如何,最终结果很好,这样做的好处是它也适用于无头浏览器,所以它也可以包含在CI中。

    ***更新2:这是一个自动执行步骤的rake任务,将其放在/ lib / tasks中

    # Coverage testing for JavaScript
    #
    # Usage:
    # Download JSCover from: http://tntim96.github.io/JSCover/ and move it to
    #   ~/Applications/JSCover-1
    # First instumentalize the javascript files:
    #   rake assets:coverage
    # Then run browser tests 
    #   rake test
    # See the results in the browser
    #   http://localhost:3000/assets/jscoverage.html
    # Don't forget to clean up instrumentalization afterwards:
    #   rake assets:clobber
    # Also don't forget to re-do instrumentalization after changing a JS file
    
    
    namespace :assets do
      desc 'Instrument all the assets named in config.assets.precompile'
      task :coverage do
        Rake::Task["assets:coverage:primary"].execute
      end
    
      namespace :coverage do
        def jscoverage_loc;Dir.home+'/Applications/JSCover-1/';end
        def internal_instrumentalize
    
          config = Rails.application.config
          target=File.join(Rails.public_path,config.assets.prefix)
    
          environment = Sprockets::Environment.new
          environment.append_path 'app/assets/javascripts'
          `rm -rf #{tmp=File.join(Rails.root,'tmp','jscover')}`
          `mkdir #{tmp}`
          `rm -rf #{target}`
          `mkdir #{target}`
    
          print 'Generating assets'
          require File.join(Rails.root,'config','initializers','assets.rb')
          (%w{application.js}+config.assets.precompile.select{|f| f.is_a?(String) && f =~ /\.js$/}).each do |f|
            print '.';File.open(File.join(target,f), 'w') {|ff| ff.write(environment[f].to_s) }
          end
          puts "\nInstrumentalizing…"
          `java -Dfile.encoding=UTF-8 -jar #{jscoverage_loc}target/dist/JSCover-all.jar -fs #{target} #{tmp} #{'--no-branch' unless ENV['C1']} --local-storage`
          puts 'Copying into place…'
          `cp -R #{tmp}/ #{target}`
          `rm -rf #{tmp}`
          File.open("#{target}/jscoverage.js",'a'){|f| f.puts 'jscoverage_isReport = true' }
    
        end
    
        task :primary => %w(assets:environment) do
          unless Dir.exist?(jscoverage_loc)
            abort "Cannot find JSCover! Download from: http://tntim96.github.io/JSCover/ and put in #{jscoverage_loc}"
          end
          internal_instrumentalize
        end
    
      end
    
    end
    

答案 1 :(得分:1)

这已添加到JSCover(在trunk中) - JSCover的相关线程为here

  

我设法让JSCover在Rails + Capybara管道中工作,但是   它需要相当多的黑客才能让它发挥作用

这些更改现在位于JSCover的主干中,并将成为1.0.5版的一部分。这里有工作示例(包括Selenium IDE记录示例)和文档。

  

进行分支检测需要一些额外的工作   因为它使用了无法轻易序列化为JSON的对象

这是一个在新代码中使用的函数。

  

无论如何,最终结果很好用

我同意。这使得JSCover可用于更高级别的工具,这些工具不适用于iFrame或通过这种方法避免的多个窗口。这也意味着可以通过两次调整将代码覆盖率添加到现有的Selenium测试中:

  1. 使测试通过JSCover代理
  2. 运行
  3. 在测试套件末尾保存覆盖率报告
  4. 有关详细信息,请参阅JSCover的文档。包含这些更改的1.0.5版应在几天内发布。