在 minitest 路由测试之前需要 运行 一些代码(插入数据库)
Need to run some code (insert into DB) before minitest route testing
由于(产品所有者的)某些要求,我不得不偏离黄金路径并为某些匹配约束的 url 覆盖资源路由。
Rails.application.routes.draw do
CATEGORY_SLUGS = Regexp.new(Category.all.collect(&:slug).join('|'))
get '/posts/:category', to: 'posts#index', as: :category_posts, constraints: { category: CATEGORY_SLUGS }
resources :posts
end
和我的测试:
require 'test_helper'
class PotsControllerTest < ActionDispatch::IntegrationTest
# routes
test "/posts/:category" do
Fabricate(:category, slug: 'rails')
assert_recognizes({controller: 'posts', action: 'index', category: 'rails' }, 'posts/rails')
end
测试显然失败了,因为在测试开始之前很久就已经绘制了路线,而 Category
在那个时候还不存在。
除了CATEGORY_SLUGS
或测试中的任何东西,还有什么好的选择可以稍后绘制路线吗?
在本例中使用 Fabricate
调用进行测试设置后,您可以请求 Rails 重新加载其路由:
Rails.application.reload_routes!
这应该确保在您的 assert_recognizes
调用之前生成动态路由。
这种方法(使用来自 ActiveRecord 模型的数据在路由配置中构建约束)有严重的缺点。不仅几乎不可能正确测试它,而且每当类别更改时您还必须重新启动应用程序,以便重新构建约束。
我建议将逻辑移至控制器操作。您将为此付出很小的性能代价(渲染 Post 时需要额外的数据库查询),但这绝对是值得的。如有必要,可以通过为类别引入查询缓存来缓解这种情况。
路由:
Rails.application.routes.draw do
resources :posts
end
控制器:
class PostsController < ActionController::Base
def show
category = Category.find_by_slug params[:id]
if category
# ... render a Category
return
end
post = Post.find_by_slug params[:id]
# ... render a Post
end
由于(产品所有者的)某些要求,我不得不偏离黄金路径并为某些匹配约束的 url 覆盖资源路由。
Rails.application.routes.draw do
CATEGORY_SLUGS = Regexp.new(Category.all.collect(&:slug).join('|'))
get '/posts/:category', to: 'posts#index', as: :category_posts, constraints: { category: CATEGORY_SLUGS }
resources :posts
end
和我的测试:
require 'test_helper'
class PotsControllerTest < ActionDispatch::IntegrationTest
# routes
test "/posts/:category" do
Fabricate(:category, slug: 'rails')
assert_recognizes({controller: 'posts', action: 'index', category: 'rails' }, 'posts/rails')
end
测试显然失败了,因为在测试开始之前很久就已经绘制了路线,而 Category
在那个时候还不存在。
除了CATEGORY_SLUGS
或测试中的任何东西,还有什么好的选择可以稍后绘制路线吗?
在本例中使用 Fabricate
调用进行测试设置后,您可以请求 Rails 重新加载其路由:
Rails.application.reload_routes!
这应该确保在您的 assert_recognizes
调用之前生成动态路由。
这种方法(使用来自 ActiveRecord 模型的数据在路由配置中构建约束)有严重的缺点。不仅几乎不可能正确测试它,而且每当类别更改时您还必须重新启动应用程序,以便重新构建约束。
我建议将逻辑移至控制器操作。您将为此付出很小的性能代价(渲染 Post 时需要额外的数据库查询),但这绝对是值得的。如有必要,可以通过为类别引入查询缓存来缓解这种情况。
路由:
Rails.application.routes.draw do
resources :posts
end
控制器:
class PostsController < ActionController::Base
def show
category = Category.find_by_slug params[:id]
if category
# ... render a Category
return
end
post = Post.find_by_slug params[:id]
# ... render a Post
end