没有测试就会让写程序的开发者没有自信
这次的新项目没有想当然的选择之前一直在用 Rspec 测试框架,主要是我感觉 Rspec 里面有太多的 magic,在 helper 文件中很多 tricks, 很快相关的配置文件就非常大。这篇 Blog 说的跟我的体会很像 7 REASONS I'M STICKING WITH MINITEST AND FIXTURES IN RAILS
minitest 是 Rails4 后默认支持的测试框架,另外 rails 也提供了很多方便和强大的 assert 方法。可以参考官方文档
下面我就总结和分享一下,Rails4 新项目中 minitest 和 capybara 的集成和配置:
group :test do
gem "minitest-reporters"
gem 'capybara'
gem "connection_pool"
gem "launchy"
gem "selenium-webdriver"
gem "mocha"
gem "poltergeist"
gem 'phantomjs', :require => 'phantomjs/poltergeist'
end
minitest-reporters
是为了美化 minitest 的测试结果输出地,有颜色,有百分比。mocha
是一个方便进行 mock 和 stub 的工具require "mocha/mini_test"
require "capybara/rails"
require "capybara/poltergeist"
# 注释掉默认的driver,打开后方便切换driver测试,也可以在代码中指定current_driver
# Capybara.default_driver = :selenium
# Capybara.default_driver = :poltergeist
Capybara.javascript_driver = :poltergeist
class ActionDispatch::IntegrationTest
# 可以在功能测试中使用capybara的DSL
include Capybara::DSL
# 默认的失败测试提示不是很有用,扩展后方便调试
def assert_content(content)
assert page.has_content?(content), %Q{Expected to found "#{content}" in: "#{page.text}"}
end
def refute_content(content)
refute page.has_content?(content), %Q{Expected not to found "#{content}" in: "#{page.text}"}
end
end
# See: https://gist.github.com/mperham/3049152
class ActiveRecord::Base
mattr_accessor :shared_connection
@@shared_connection = nil
def self.connection
@@shared_connection || ConnectionPool::Wrapper.new(:size => 1) { retrieve_connection }
end
end
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
如果要测试邮件的内容,内容中一般都会有链接,所以需要在 config/environments/test.rb 中加上:
config.action_mailer.default_url_options = { host: '127.0.0.1', port: 3000 }
如果使用了 delayed_job 可以在其配置中加上:
Delayed::Worker.delay_jobs = !Rails.env.test?
表明测试环境下,邮件任务都是直接发送出去的
在 test 目录下面,新建 features 目录,专门存放网站功能测试代码
test/features/user_authentication_test.rb
require 'test_helper'
class UserAuthenticationTest < ActionDispatch::IntegrationTest
setup do
ActionMailer::Base.deliveries.clear
end
test 'user can sign up with email and password' do
visit new_user_registration_path
assert_content "注册帐号"
within '#new_user' do
fill_in 'user[email]', with: '[email protected]'
fill_in 'user[password]', with: 'abcd1234'
click_button '创建新帐号'
end
assert_equal sign_up_success_path, page.current_path
assert_content "[email protected]"
test_confirm_email
end
private
def test_confirm_email
assert_not ActionMailer::Base.deliveries.empty?
cf_email = ActionMailer::Base.deliveries.last
assert_equal ["[email protected]"], cf_email.from
assert_equal ['[email protected]'], cf_email.to
assert_equal '确认信息', cf_email.subject
assert_match /Confirm my account/, cf_email.body.to_s
end
end
所以可以看到用 minitest 写的代码都非常直接,都是纯 ruby 代码。等代码增多后,可以按照 ruby 的方式来组织,重用和重构。