我正试图使用Action Controller bug report template在Rails中解决一个奇怪的行为。
对于记录,这是模板中的控制器:
class TestController < ActionController::Base
include Rails.application.routes.url_helpers
def index
render text: 'Home'
end
end
我添加了一条缺失动作的路线:
routes.draw do
get '/' => 'test#index'
get '/missing' => 'test#missing'
end
我试图断言在跟踪该路线时引发AbstractController::ActionNotFound
:
class BugTest < Minitest::Test
include Rack::Test::Methods
def test_missing
assert_raises(AbstractController::ActionNotFound) { get '/missing' }
end
private
def app
Rails.application
end
end
预期行为:绿色测试。
实际行为:
# Running tests:
D, [2014-04-24T09:17:41.948985 #4497] DEBUG -- :
D, [2014-04-24T09:17:41.949029 #4497] DEBUG -- :
I, [2014-04-24T09:17:41.949094 #4497] INFO -- : Started GET "/missing" for 127.0.0.1 at 2014-04-24 09:17:41 +0200
F, [2014-04-24T09:17:41.951337 #4497] FATAL -- :
AbstractController::ActionNotFound (The action 'missing' could not be found for TestController):
[stacktrace]
1) Failure:
BugTest#test_missing [action_controller_gem.rb:45]:
AbstractController::ActionNotFound expected but nothing was raised.
所以,基本上,引发了异常,但Minitest声称没有提出任何内容。我很难过。
为什么Minitest不能断言AbstractController::ActionNotFound
被提出?我调查了Rack::Test::Methods
以排除get
适用于线程或其他东西但无法找到任何内容。
我也看过implementation of assert_raises
- 没什么明显的。
为什么assert_raises(AbstractController::ActionNotFound) { get '/missing' }
没有通过?
(没关系这个事实已经在Rails中测试了。我正试图通过这个实际交易。)
答案 0 :(得分:12)
这不是assert_raises
的问题,继续正常工作。您遇到的问题是,您在Rails应用程序中引发的异常将由您的Rails应用程序处理,而不会传播到您的测试中。调用get '/missing'
会引发AbstractController::ActionNotFound
错误,但您的应用会处理错误并向客户端(您的测试)返回相应的响应(404或500)。
好的,那么你将如何测试你的控制器确实引发了你期望的错误?通常,您只需使用ActionController::TestCase
测试来测试控制器。但是,当您在ActionController::TestCase
中的控制器上调用操作时,您会收到不同的错误。以下是:
require "test_helper"
class TestControllerTest < ActionController::TestCase
def test_missing
assert_raises AbstractController::ActionNotFound do
get :missing
end
end
end
产生以下输出:
1) Failure:
TestControllerTest#test_missing [test/controllers/test_controller_test.rb:6]:
[AbstractController::ActionNotFound] exception expected, not
Class: <ActionController::UrlGenerationError>
Message: <"No route matches {:action=>\"missing\", :controller=>\"test\"}">
---Backtrace---
test/controllers/test_controller_test.rb:7:in `block in test_missing'
test/controllers/test_controller_test.rb:6:in `test_missing'
---------------
原因是因为ActionController::TestCase
知道路线并且不允许调用不在路线中的动作。但这正是您要测试的内容。并且,我假设您没有使用ActionController::TestCase
。
此时我想知道你是不是在测试一些你不应该做的事情。也许您应该允许Rails完成其工作并相信它的行为正确。但是,嘿,我们已经到了这么远,为什么不一直走下去测试Rails测试的东西。我们不是通过完整的Rails应用程序进行调用,而是尝试直接调用TestController
。如果我们创建一个新的控制器实例,我们可以要求它处理一个动作,即使该动作没有在控制器上定义。但要做到这一点,我们必须深入了解ActionController的工作原理并使用AbstractController#process
方法:
require "test_helper"
class TestControllerTest < Minitest::Test
def test_missing
assert_raises AbstractController::ActionNotFound do
TestController.new.process :missing
end
end
end
现在我们要求控制器处理一个不存在的动作并测试控制器的行为是否符合预期。耶?