这篇博客是我们 《Rails 5 系列文章》 中的一篇。
在 Rails 5 项目里使用 bin/rails -h
,你将看到跑测试的一个新命令(rails test
)
$ bin/rails -h
Usage: rails COMMAND [ARGS]
The most common rails commands are:
generate Generate new code (short-cut alias: "g")
console Start the Rails console (short-cut alias: "c")
server Start the Rails server (short-cut alias: "s")
test Run tests (short-cut alias: "t")
在 Rails 5 之前,我们都用 bin/rake test
来跑测试,现在我们可以使用 bin/rails test
了。它不仅仅只是替换了原来的 rake 旧命令,而且它背靠了一个取精华于 RSpec,minitest-reporters,maxitest 及其他的 test runner
。
让我们一起看看 bin/rails test
能做些啥。
现在跑单个测试已经可以使用行号了。
$ bin/rails test test/models/user_test.rb:27
Rails 会机智地运行 user_test.rb 中的第 27 行所在位置的测试。请注意第 27 行甚至不必是该测试的首行,如下例所示:
22 def test_valid_user
23 hash = { email: '[email protected]',
24 first_name: 'John',
25 last_name: 'Smith' }
26
27 user = User.new hash
28
29 assert user.valid?
30 end
上例中,只要给出的行号在 22 至 30 之间,test_valid_user
就会被执行。
你仍可以给出多个路径来跑多个测试。
$ bin/rails test test/models/user_test.rb:27 test/models/post_test.rb:42
甚至给出多个目录来跑其中的所有测试。
$ bin/rails test test/controllers test/integration
当一个测试失败了,Rails 将显示一行命令用来单独跑错误的那个测试,如:
$ bin/rails t
Run options: --seed 51858
# Running:
.F
Failure:
PostsControllerTest#test_should_get_new:
Expected response to be a <success>, but was a <302> redirect to <http://test.host/posts>
bin/rails test test/controllers/posts_controller_test.rb:15
我只需拷贝 bin/rails test test/controllers/posts_controller_test.rb:15
即可重跑错误测试。
默认情况,当测试失败,rails 会报告测试失败然后跳到下一个测试。如果你想遇到错误就停下可以添加 -f
参数。
$ bin/rails t -f
Run options: -f --seed 59599
# Running:
..F
Failure:
PostsControllerTest#test_should_get_new:
Expected response to be a <success>, but was a <302> redirect to <http://test.host/posts>
bin/rails test test/controllers/posts_controller_test.rb:15
Interrupted. Exiting...
Finished in 0.179125s, 16.7481 runs/s, 22.3308 assertions/s.
3 runs, 4 assertions, 1 failures, 0 errors, 0 skips
默认情况,当测试失败,rails 会打印 F
且详细报告哪个断言出错及如何重测。
假如你希望一个干净的 .
和 F
然后再统一打印错误详情,可以使用 -d
参数。
$ bin/rails t -d
Run options: -d --seed 29906
# Running:
..F...F
Finished in 0.201320s, 34.7704 runs/s, 49.6721 assertions/s.
1) Failure:
PostsControllerTest#test_should_create_post [/Users/prathamesh/Projects/fun/rails-5-test-runner-app/test/controllers/posts_controller_test.rb:19]:
"Post.count" didn't change by 1.
Expected: 3
Actual: 2
2) Failure:
PostsControllerTest#test_should_get_new [/Users/prathamesh/Projects/fun/rails-5-test-runner-app/test/controllers/posts_controller_test.rb:15]:
Expected response to be a <success>, but was a <302> redirect to <http://test.host/posts>
7 runs, 10 assertions, 2 failures, 0 errors, 0 skips
Failed tests:
bin/rails test test/controllers/posts_controller_test.rb:19
bin/rails test test/controllers/posts_controller_test.rb:15
默认情况,当测试遇到一个错误,输出中并不包含全部的回溯信息,这将使调试变得困难。
Error:
PostsControllerTest#test_should_create_post:
NameError: undefined local variable or method `boom' for #<PostsController:0x007f86bc62b728>
app/controllers/posts_controller.rb:29:in `create'
test/controllers/posts_controller_test.rb:20:in `block (2 levels) in <class:PostsControllerTest>'
test/controllers/posts_controller_test.rb:19:in `block in <class:PostsControllerTest
当我们使用 -b
参数后,就会显示完整的错误回溯信息:
$ bin/rails t -b
Error:
PostsControllerTest#test_should_create_post:
NameError: undefined local variable or method `boom' for #<PostsController:0x007fc53c4eb868>
/rails-5-test-runner-app/app/controllers/posts_controller.rb:29:in `create'
/sources/rails/actionpack/lib/action_controller/metal/basic_implicit_render.rb:4:in `send_action'
/sources/rails/actionpack/lib/abstract_controller/base.rb:183:in `process_action'
/sources/rails/actionpack/lib/action_controller/metal/rendering.rb:30:in `process_action'
/sources/rails/actionpack/lib/abstract_controller/callbacks.rb:20:in `block in process_action'
/sources/rails/activesupport/lib/active_support/callbacks.rb:126:in `call'
.....
/sources/rails/activesupport/lib/active_support/testing/assertions.rb:71:in `assert_difference'
/rails-5-test-runner-app/test/controllers/posts_controller_test.rb:19:in `block in <class:PostsControllerTest>'
测试运行器也会通过提供一些便利参数来借助 minitest 的力量。
现在我们可以用 -s
开关参数来提供自己的种子值。
$ bin/rails t --s 42000
这里补充一下关于 seed 值,由于 minitest 使用 seed 值来随机化测试,因此 seed 值的作用就在于控制随机序列的顺序,也就是说,如果你希望重跑的测试跟上一次的顺序一样,可以设置跟上一次测试相同的 seed 值来做到。详情可以参考 MiniTest
-n
开关参数可以通过给定的字符串或者正则表达式来匹配跑测试
$ bin/rails t -n "/create/"
Run options: -n /create/ --seed 24558
# Running:
E
Error:
PostsControllerTest#test_should_create_post:
NameError: undefined local variable or method `boom' for #<PostsController:0x007faa39c2df90>
app/controllers/posts_controller.rb:29:in `create'
test/controllers/posts_controller_test.rb:20:in `block (2 levels) in <class:PostsControllerTest>'
test/controllers/posts_controller_test.rb:19:in `block in <class:PostsControllerTest>'
bin/rails test test/controllers/posts_controller_test.rb:18
Finished in 0.073857s, 13.5396 runs/s, 0.0000 assertions/s.
1 runs, 0 assertions, 0 failures, 1 errors, 0 skips
使用 -v
来启用啰嗦输出,它会输出每个测试的运行时间,用来帮助我们判断较慢的测试。
$ bin/rails t -v
Run options: -v --seed 30118
# Running:
PostsControllerTest#test_should_destroy_post = 0.07 s = .
PostsControllerTest#test_should_update_post = 0.01 s = .
PostsControllerTest#test_should_show_post = 0.10 s = .
PostsControllerTest#test_should_create_post = 0.00 s = F
Failure:
PostsControllerTest#test_should_create_post:
"Post.count" didn't change by 1.
Expected: 3
Actual: 2
bin/rails test test/controllers/posts_controller_test.rb:19
PostsControllerTest#test_should_get_new = 0.02 s = .
PostsControllerTest#test_should_get_index = 0.01 s = .
PostsControllerTest#test_should_get_edit = 0.00 s = .
Finished in 0.210071s, 33.3220 runs/s, 47.6028 assertions/s.
7 runs, 10 assertions, 1 failures, 0 errors, 0 skips
现在默认情况下,我们就能得到亮彩输出,无需再添加额外的 gem 了。
拥有了以上这些优秀的特性,无疑改善了 Rails 5 应用的测试体验。Rails 已经整装待发所有以上特性,因此你无需在四处寻找各种包和组件来支持以上功能了。
作者 Prathamesh Sonpatki 于 2016.1.3