Gem Rails 3.2.13 使用 Spork + Guard + RSpec + Capybara

juanito · 2012年04月30日 · 最后由 juanito 回复于 2016年06月07日 · 12518 次阅读

读这篇比我的好

Ruby on Rails 教程第二版,3.6 高级技术

比较匆忙的同学请看

  1. rails new appname --skip-test-unit --skip-bundle
  2. 复制 Gemfile,替换掉项目下的 Gemfile:
  • OSX

  • Linux

  • Windows

    安装需要的 Gems,你有两个选择:

    • bundle install ,之后使用 bundle exec xxx
    • bundle install --binstubs ,之后使用 bin/xxx
  1. rails generate rspec:install
  2. 运行 bin/guard init rspec && bin/guard init spork
  3. 复制这个 Guardfile,覆盖掉项目下的 Guardfile。
  4. 添加 --drb 至项目的根目录下的 .rspec
  5. 复制这个 spec/spec_helper.rb,覆盖 spec/spec_helper.rb

  6. bundle exec spork --bootstrapbin/sprok --bootstrap

  7. bundle exec guardbin/guard

-- FINISH --

有 10 分钟的同学请看

为什么使用 Guard

  1. 要切回终端机敲 RSpec 命令
  2. 启动速度太慢 (使用 Spork 来加速)

Guard 人如其名,自动侦测改动并运行测试。

配置

添加 guard-rspec gem:

Gemfile:

group :development, :test do  
  gem 'guard-rspec', '1.2.1'
end

:test group 加入一些相依的 Gems,OSX 可能需要安装 growl-notify

Growlnotify 效果圖:

*Growlnotify* 效果圖

MacOSX

gem 'rb-fsevent', '0.9.1', :require => false
gem 'growl', '1.0.3'

Linux

gem 'rb-inotify', '0.8.8'
gem 'libnotify', '0.5.9'

Windows

gem 'rb-fchange', '0.0.5'
gem 'rb-notifu', '0.0.4'
gem 'win32console', '1.3.0'

范例 Gemfile,放在 Gist:

MacOSX / Linux / Windows

Gemfile 配置好运行 bundle install ,初始化 Guard:

bundle exec guard init rspec

或是运行 bundle install --binstubs,初始化 Guard:

bin/guard init rspec

会产生一个 Guardfile,最上方加入此行:

require 'active_support/core_ext'

并改动此行 guard 'rspec', :version => 2 do

guard 'rspec', :version => 2, :all_after_pass => false do

确保 Guard 一个失败测试通过以后,不会运行所有的测试(加快 红绿重构 周期)

再添加:

guard 'rspec', :version => 2, :all_after_pass => false do
  .
  .
  .
  watch(%r{^app/controllers/(.+)_(controller)\.rb$})  do |m|
    ["spec/routing/#{m[1]}_routing_spec.rb",
     "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb",
     "spec/acceptance/#{m[1]}_spec.rb",
     (m[1][/_pages/] ? "spec/requests/#{m[1]}_spec.rb" :
                       "spec/requests/#{m[1].singularize}_pages_spec.rb")]
  end
  watch(%r{^app/views/(.+)/}) do |m|
    (m[1][/_pages/] ? "spec/requests/#{m[1]}_spec.rb" :
                       "spec/requests/#{m[1].singularize}_pages_spec.rb")
  end
  .
  .
  .
end

当 integration tests 及 views 有变动时,会自动运行测试。

这些都设置好了,启动 guard

bundle exec guard

bin/guard

更多信息请参考:Guard Github 页面

使用 Spork 来加速测试

运行 RSpec 很慢的原因是每次都得重加载整个 Rails 环境。Spork 测试服务器透过加载 Rails 环境,并维护一个进程池 (pool of processes) 给之后的测试使用。跟 Guard 搭配使用顺风顺水。

配置 Gemfile,将此行加入 :test group

gem 'guard-spork', '0.3.2'
gem 'spork', '0.9.0'

范例 Gemfile,放在 Gist:

运行 bundle install 并运行 spork:

bundle exec spork --bootstrap

运行 bundle install --binstubs 并运行 spork:

spork --bootstrap # or bin/spork --bootstrap

添加需加载的环境信息至 spec/spec_helper.rb 里的 Spork.prefork

require 'rubygems'
require 'spork'

Spork.prefork do
  # Loading more in this block will cause your tests to run faster. However,
  # if you change any configuration or code from libraries loaded here, you'll
  # need to restart spork for it take effect.
  # This file is copied to spec/ when you run 'rails generate rspec:install'
  ENV["RAILS_ENV"] ||= 'test'
  require File.expand_path("../../config/environment", __FILE__)
  require 'rspec/rails'
  require 'rspec/autorun'

  # Requires supporting ruby files with custom matchers and macros, etc,
  # in spec/support/ and its subdirectories.
  Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

  RSpec.configure do |config|
    # == Mock Framework
    #
    # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
    #
    # config.mock_with :mocha
    # config.mock_with :flexmock
    # config.mock_with :rr
    config.mock_with :rspec

    # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
    config.fixture_path = "#{::Rails.root}/spec/fixtures"

    # If you're not using ActiveRecord, or you'd prefer not to run each of your
    # examples within a transaction, remove the following line or assign false
    # instead of true.
    config.use_transactional_fixtures = true

    # If true, the base class of anonymous controllers will be inferred
    # automatically. This will be the default behavior in future versions of
    # rspec-rails.
    config.infer_base_class_for_anonymous_controllers = false
  end
end

Spork.each_run do
  # This code will be run each time you run your specs.

end

启动 Spork 服务器:

之前使用 bundle install

bundle exec spark

之前使用 bundle install --binstubs

bin/spork

加入此行至 .rspec ,让 RSpec 缺省使用 spork:

--drb

提示

如果改动了 routes.rb 需重启 Spork 服务器,如果你觉得测试是对的,但是失败了,也可以重启 Spork 服务器试试看。

更多信息请参考 Spork Github 页面

Guard 搭配 Spork

有了 Guard 与 Spork 以后,让它们合体:

bundle exec guard init spork
bin/guard init spork

加入此段代码至 Guardfile:

guard 'spork', :rspec_env => { 'RAILS_ENV' => 'test' } do
  watch('config/application.rb')
  watch('config/environment.rb')
  watch(%r{^config/environments/.+\.rb$})
  watch(%r{^config/initializers/.+\.rb$})
  watch('Gemfile')
  watch('Gemfile.lock')
  watch('spec/spec_helper.rb')
  watch('test/test_helper.rb')
  watch('spec/support/')
end

guard 'rspec', :version => 2, :all_after_pass => false, :cli => '--drb' do
  .
  .
  .
end

现在全都设定好了,以后只要

bundle exec guardbin/guard

Guard 就会自动启动 Spork 服务器并侦测你的改动!

一个常见的错误

ERROR: Could not start Spork server for Test::Unit & RSpec after 30 seconds.

如果没有使用 Test::Unit,把 test/ 目录移除或更名即可。

:D

不错,不过建议楼主可以用 guard-spork,这样一个 guard 可以全包了

贴一个傻瓜型 Gemfile 带了 guard,livereload 等等一体化自动测试

require 'rbconfig'
HOST_OS = RbConfig::CONFIG['host_os']
source 'http://rubygems.org'

gem 'rails', '3.2.3'

# Gems used only for assets and not required
# in production environments by default.
group :assets do
  gem 'sass-rails',   '~> 3.2.3'
  gem 'coffee-rails', '~> 3.2.1'
  gem 'uglifier', '>= 1.0.3'
end

gem 'jquery-rails'
gem 'rspec-rails' ,:group => [:development,:test]

# jquery-ui
# gem 'jquery-ui-rails'

# bootstrap
# gem 'anjlab-bootstrap-rails', :require => 'bootstrap-rails',:git => 'git://github.com/anjlab/bootstrap-rails.git'

if HOST_OS =~ /linux/i
  gem 'therubyracer', '>= 0.8.2'
end
case HOST_OS
  when /darwin/i
    gem 'rb-fsevent', :group => :development
    gem 'growl', :group => :development
    gem 'guard-pow', :group => :development
  when /linux/i
    gem 'libnotify', :group => :development
    gem 'rb-inotify', :group => :development
  when /mswin|windows/i
    gem 'rb-fchange', :group => :development
    gem 'win32console', :group => :development
    gem 'rb-notifu', :group => :development
end


# Use unicorn as the web server
# gem 'unicorn'

# Deploy with Capistrano
# gem 'capistrano'

# To use debugger
# gem 'ruby-debug19', :require => 'ruby-debug'

group :test do
  # Pretty printed test output
  gem 'turn', :require => false
  gem 'factory_girl_rails' , "~> 1.1.0" ,:require => false
  gem 'database_cleaner', ">= 0.6.7"
  gem 'mongoid-rspec', ">= 1.4.4"
  gem "capybara",">= 1.1.1"
  gem "launchy", ">= 2.0.5"
  gem 'guard-spork'
  gem 'spork', '~> 0.9.0'
  gem "guard-rspec"
  gem 'guard-livereload'
  gem 'guard-bundler'
end



执行guard init 然后按照需要调整 Guardfile,确保 spork 在 rspec 的上面

# A sample Guardfile
# More info at https://github.com/guard/guard#readme
guard 'livereload' do
  watch(%r{app/.+\.(erb|haml)})
  watch(%r{app/helpers/.+\.rb})
  watch(%r{(public/|app/assets).+\.(css|js|html)})
  watch(%r{(app/assets/.+\.css)\.s[ac]ss}) { |m| m[1] }
  watch(%r{(app/assets/.+\.js)\.coffee}) { |m| m[1] }
  watch(%r{config/locales/.+\.yml})
end

guard 'pow' do
  watch('.powrc')
  watch('.powenv')
  watch('.rvmrc')
  watch('Gemfile')
  watch('Gemfile.lock')
  watch('config/application.rb')
  watch('config/environment.rb')
  watch(%r{^config/environments/.*\.rb$})
  watch(%r{^config/initializers/.*\.rb$})
  watch(%r{^config/settings(\.local)?\.yml$})
end

guard 'spork', :cucumber_env => { 'RAILS_ENV' => 'test' }, :rspec_env => { 'RAILS_ENV' => 'test' } do
  watch('config/application.rb')
  watch('config/environment.rb')
  watch(%r{^config/environments/.+\.rb$})
  watch(%r{^config/initializers/.+\.rb$})
  watch('spec/spec_helper.rb')
end

guard 'rspec', :version => 2 ,:cli => "--drb",:notification => true do
  watch(%r{^spec/.+_spec\.rb$})
  watch(%r{^lib/(.+)\.rb$})     { |m| "spec/lib/#{m[1]}_spec.rb" }
  watch('spec/spec_helper.rb')  { "spec/" }

  # Rails example
  watch(%r{^spec/.+_spec\.rb$})
  watch(%r{^app/(.+)\.rb$})                           { |m| "spec/#{m[1]}_spec.rb" }
  watch(%r{^lib/(.+)\.rb$})                           { |m| "spec/lib/#{m[1]}_spec.rb" }
  watch(%r{^app/controllers/(.+)_(controller)\.rb$})  { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
  watch(%r{^spec/support/(.+)\.rb$})                  { "spec/" }
  watch('spec/spec_helper.rb')                        { "spec/" }
  watch('config/routes.rb')                           { "spec/routing" }
  watch('app/controllers/application_controller.rb')  { "spec/controllers" }
  # Capybara request specs
  watch(%r{^app/views/(.+)/.*\.(erb|haml)$})          { |m| "spec/requests/#{m[1]}_spec.rb" }
end

然后参照楼主的文章设置一下 spec_helper.rb

执行guard即可开始自动测试,自动重启服务,自动 bundle 等等

#3 楼 @aNdReW_Qx 谢谢提醒,我也有用 guard-spork,好用!

guard 挺好的,只是我每写几行代码就很习惯地保存一下,guard 跑个不停...而且有时会出现一些灵异错误怎么跑都跑不过,最后重启 guard 才过了,可能没配置好。@Juanito 有没有出现过这种问题?

#5 楼 @Zernel 有些改动需要重启才能测试。。。比如改了个 route,要是觉得测试对了,但是跑不过,就重启 guard 吧。

#6 楼 @Juanito 现在在做的项目没有选用 guard,等下次用的时候参考下你的配置,谢谢分享 XD

不错,很帅。

#3 楼 @aNdReW_Qx 这个 Gemfile 非常适合经常在不同系统上写同一个项目的人。

#9 楼 @AlphaLiu 嗯,你可以配合:platform => :jruby 这样的使用,另外如果经常跨平台,注意再 gemfile 里限 gem 版本,然后不要让 Gemfile.lock 进入 repo

#3 楼 @aNdReW_Qx 有个问题,guard-livereload 怎么连不上浏览器呢?我都已经装了浏览器扩展,但是当我修改一个 view 的时候,浏览器都没有自动刷新。我在 ubuntu 下,guardfile 里面的 pow 段没用,被我删掉了。

看了这篇文章,才真正知道咱社区常说的 Guard 是个啥玩意儿。

之前一直以为是一个 Mac 下专用的,类似于 autotest 的玩意儿,现在才明白,Guard 原来是全方位的...

太谢谢@Juanito啦。

archlinux+openbox 通知测试结果失败?

学习了。

16 楼 已删除

bundle exec guard init spec ,新版本中应改为 bundle exec guard init rspec ,另外,在 windows xp,还需要 gem wdm ,否则出错。

另外,问下,怎么取消提示音。。

我这边 windows7 用 unit test 在 opensuse 下什么问题都没有 切 windows 下面提示,然后修改文件是没有反应的。也就是说没有监视到文件的变化

Please add the following to your Gemfile to avoid polling for changes:
  require 'rbconfig'
  if RbConfig::CONFIG['target_os'] =~ /mswin|mingw|cygwin/i
    gem 'wdm', '>= 0.1.0'
  end

然后我加了 wdm,再然后

11:21:07 - INFO - Guard is now watching at 'F:/src/guard'
Process finished with exit code -1073741819

rubymine 中会有Process finished with exit code -1073741819 而 cmd 终端显示 now watching 之后就直接显示 F:\src\guard>

同样的代码,opensuse 完全木有问题,求问是怎么回事

guardfile

guard 'spork', :test_unit => true, :test_unit_env => {'RAILS_ENV' => 'test'}, :wait => 60 do
  watch('config/application.rb')
  watch('config/environment.rb')
  watch('config/environments/test.rb')
  watch(%r{^config/initializers/.+\.rb$})
  watch('Gemfile.lock')
  watch('spec/spec_helper.rb') { :rspec }
  watch('test/test_helper.rb') { :test_unit }
  watch(%r{features/support/}) { :cucumber }
end

guard :test, :drb => true, :all_after_pass => false, :all_on_start => false do
  watch(%r{^test/.+_test\.rb$})
  watch('test/test_helper.rb')  { 'test' }

  # Non-rails
  watch(%r{^lib/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" }
  watch(%r{^app/models/(.+)\.rb$})                   { |m| "test/unit/#{m[1]}_test.rb" }
  watch(%r{^app/controllers/(.+)\.rb$})              { |m| "test/functional/#{m[1]}_test.rb" }
  watch(%r{^app/views/(.+)/.+\.erb$})                { |m| "test/functional/#{m[1]}_controller_test.rb" }
  watch(%r{^app/views/.+$})                          { 'test/integration' }
  watch('app/controllers/application_controller.rb') { ['test/functional', 'test/integration'] }
end

gemfile

source 'https://ruby.taobao.org'
require 'rbconfig'
if RbConfig::CONFIG['target_os'] =~ /mswin|mingw|cygwin/i
  gem 'wdm', '>= 0.1.0'
end
  ...
group :development, :test do
    gem "guard-rails"
    gem 'spork-testunit'
    gem 'guard-spork'
    gem 'guard-test', '~> 1.0.0'
    gem 'ruby-prof' 
    gem 'pry'
    gem 'pry-nav'
  gem 'childprocess'
end

group :test do
  gem "shoulda", "> 3.3.2"
  gem "mocha", "~> 0.13.3"
  gem 'capybara', '~> 2.0.0'
  gem 'nokogiri', '< 1.6.0'
  gem 'factory_girl'
  gem 'rb-fchange', '0.0.5'
  gem 'rb-notifu', '0.0.4'
  gem 'win32console', '~>1.3.0'
end
  ...

经典好帖!

juanito 1000 个小时学会 Rails - 004 神秘的 X 项目 提及了此话题。 06月07日 21:43
需要 登录 后方可回复, 如果你还没有账号请 注册新账号