如何在 rspec 中编写 Rails 3.1 引擎控制器测试? [英] How do I write a Rails 3.1 engine controller test in rspec?
问题描述
我已经用命名空间 Posts 编写了一个 Rails 3.1 引擎.因此,我的控制器在 app/controllers/posts/中,我的模型在 app/models/posts 等中.我可以很好地测试模型.一种模型的规格看起来像...
I have written a Rails 3.1 engine with the namespace Posts. Hence, my controllers are found in app/controllers/posts/, my models in app/models/posts, etc. I can test the models just fine. The spec for one model looks like...
module Posts
describe Post do
describe 'Associations' do
it ...
end
...一切正常.
但是,控制器的规格不起作用.Rails 引擎安装在/posts,而控制器是 Posts::PostController.因此,测试寻找控制器路由为帖子/帖子.
However, the specs for the controllers do not work. The Rails engine is mounted at /posts, yet the controller is Posts::PostController. Thus, the tests look for the controller route to be posts/posts.
describe "GET index" do
it "assigns all posts as @posts" do
Posts::Post.stub(:all) { [mock_post] }
get :index
assigns(:posts).should eq([mock_post])
end
end
产生...
1) Posts::PostsController GET index assigns all posts as @posts
Failure/Error: get :index
ActionController::RoutingError:
No route matches {:controller=>"posts/posts"}
# ./spec/controllers/posts/posts_controller_spec.rb:16
我在测试应用程序的路由文件中尝试了各种技巧......:命名空间等,但无济于事.
I've tried all sorts of tricks in the test app's routes file... :namespace, etc, to no avail.
我该如何进行这项工作?似乎不会,因为引擎将控制器放在/posts,但命名空间将控制器放在/posts/posts 以进行测试.
How do I make this work? It seems like it won't, since the engine puts the controller at /posts, yet the namespacing puts the controller at /posts/posts for the purpose of testing.
推荐答案
我假设您正在使用一个虚拟的 rails 应用程序测试您的引擎,就像由 enginex.
I'm assuming you're testing your engine with a dummy rails app, like the one that would be generated by enginex.
您的引擎应该安装在虚拟应用程序中:
Your engine should be mounted in the dummy app:
在spec/dummy/config/routes.rb
:
Dummy::Application.routes.draw do
mount Posts::Engine => '/posts-prefix'
end
我的第二个假设是您的引擎是孤立的:
My second assumption is that your engine is isolated:
在 lib/posts.rb
中:
module Posts
class Engine < Rails::Engine
isolate_namespace Posts
end
end
我不知道这两个假设是否真的需要,但我自己的引擎就是这样构建的.
I don't know if these two assumptions are really required, but that is how my own engine is structured.
解决方法很简单,而不是这个
The workaround is quite simple, instead of this
get :show, :id => 1
使用这个
get :show, {:id => 1, :use_route => :posts}
:posts
符号应该是引擎的名称,而不是它的安装路径.
The :posts
symbol should be the name of your engine and NOT the path where it is mounted.
这是有效的,因为 get 方法参数直接传递给 ActionDispatch::Routing::RouteSet::Generator#initialize
(定义 here),依次使用 @named_route
Rack::Mount::RouteSet#generate
的正确路线(参见 这里 和 这里).
This works because the get method parameters are passed straight to ActionDispatch::Routing::RouteSet::Generator#initialize
(defined here), which in turn uses @named_route
to get the correct route from Rack::Mount::RouteSet#generate
(see here and here).
深入 Rails 内部很有趣,但很耗时,我不会每天都这样做 ;-) .
Plunging into the rails internals is fun, but quite time consuming, I would not do this every day ;-) .
HTH
这篇关于如何在 rspec 中编写 Rails 3.1 引擎控制器测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!