准备一个全新的 Rails 应用,今天我们了解一下 Rails 应用的测试。
创建测试
先为我们要创建的控制器创建一个测试,比如我要创建一个名字是 Pages 的控制器,对这个控制器的测试可以放在 test/controllers 目录的下面,创建一个测试文件,文件名里可以包含控制器的名字,再加上一个 test 后缀:
test/controllers/pages_controller_test.rb
在这个测试文件里,先 require 测试需要的一个助手,名字是 test_helper。每个测试都是一个类,让它继承 ActionDispatch::IntegrationTest。在这个测试文件里添加:
require 'test_helper' class PagesControllerTest < ActionDispatch::IntegrationTest end
在这个测试类里面,每个测试的形式像这样:
test "说明一下要测试的是什么" do # 具体要做的测试 end
比如我要在 Pages 里面添加一个 about 动作,它处理的是对 /about 这个静态页面的请求。对这个方法的测试可以使用 get 方法请求一下这个静态页面地址,然后断言它会返回 http 的成功状态码,也就是 200。这个测试会像这样:
class PagesControllerTest < ActionDispatch::IntegrationTest test "should get about" do get about_url assert_response :success end end
先 get 一下 about 页面的地址,这个地址我们用了一个路由的助手方法。断言用了 assert_response,断言的是响应,:success 对应的是一个 http 的状态码,也就是 200 ,表示成功的得到了响应。这个测试的意思就是请求 /about 这个地址,断言得到的响应是 200。
运行测试
再去运行一下这个测试:
rails test
会看到一个错误:
undefined local variable or method `about_url'
提示不认识 about_url,这是一个助手方法,创建了对应的路由以后才会得到这个方法。我们再为应用添加一些东西。先创建 Pages 控制器,然后给它添加 about 方法,再去添加一条路由。
控制器:app/controllers/pages_controller.rb
class PagesController < ApplicationController def about end end
路由:config/routes.rb
Rails.application.routes.draw do get '/about', to: 'pages#about' end
再次运行测试:
rails test
会提示:
ActionController::UnknownFormat: PagesController#about is missing a template for this request format and variant.
意思是 about 方法用的视图还不存在,再去为它创建一个对应的视图。
视图:app/views/pages/about.html.erb
<h1>about</h1>
再次运行测试:
rails test
这次就不会再提示错误了,看一下测试的运行的状态,现在会是:
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
测试报告
使用 minitest-reporters 这个 gem,可以去定制一下运行测试返回的报告,你可以使用不同风格的测试报告。https://github.com/kern/minitest-reporters
首先去为 test 环境添加一个 gem,打开 Gemfile,添加:
group :test do gem 'minitest-reporters', '1.1.9' end
再打开测试的助手:test/test_helper.rb。
添加两行代码:
require "minitest/reporters" Minitest::Reporters.use!
执行:
bundle install
再次运行测试,现在的测试报告看起来是这样的:
默认的 minitest-reporters 的测试报告会带一个进度条。我们可以使用其它风格的报告,比如配置一下使用 Spec 风格的报告:
test/test_helper.rb
把:
Minitest::Reporters.use!
换成:
Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
现在的测试报告看起来是这样的:
测试页面标签内容
我想测试请求回来的一个页面上的某个元素里的值,比如页面的标题必须等于什么,这种断言可以使用 assert_select。
test/controllers/pages_controller_test.rb
class PagesControllerTest < ActionDispatch::IntegrationTest test "should get about" do get about_url assert_response :success assert_select "title", "about | App" end end
在 should get about 这个测试里,添加了一条新的断言:
assert_select "title", "about | App"
意思就是请求 /about ,响应回来的内容里面,它的 title 标签的值要是 “about | App”。
运行一下测试,会报错:
再去编辑一下视图的默认的布局:app/views/layouts/application.html.erb,修改一下它的 title 标签的值:
<title><%= yield :title %> | App</title>
上面定义了一个 :title 区域,这个区域的内容可以在视图里提供给它。
编辑视图:app/views/pages/about.html.erb,添加一行:
<% provide(:title, 'about') %>
意思是,为布局的 :title 区域提供的内容是 about 。这样使用这个视图的页面的 title 元素里的值就会是 about | App。
运行测试,这次就会成功了:
setup
在运行每个测试之前,可以使用 setup 方法去配置一些东西:
class PagesControllerTest < ActionDispatch::IntegrationTest def setup @app_name = "App" end test "should get about" do get about_url assert_response :success assert_select "title", "about | #{@app_name}" end endRuby
评论
做测试一般是要测试哪些方面的内容?测最终结果的类型?
8 年 1个月 以前
我觉得测试就是测试的你想要的结果。做出一些断言,如果断言不成立,你的应用就会出问题。
8 年 1个月 以前
皓哥,可否讲解下如何在生产环境下,利用docker迁移和部署 rails网站,感觉docker的课程就剩这一个环节了,谢谢!
8 年 2 天 以前