测试 Rails 3 控制器时出现一些意外错误
我有一个这样定义的服务模型:
class Service < ActiveRecord::Base
attr_accessible :service_type #, ...
SERVICE_TYPES = {
:restaurant => "restaurant",
:retailer => "retailer"
}
SERVICE_TYPES.values.each do |method|
define_method method.pluralize.to_sym do
where(:service_type => method)
end
end
def domestic
where(:country => 'USA')
end
def international
where("country != 'USA'")
end
end
我决定不对不同的服务使用传统的 STI 模式,因为它们都具有相同的属性,并且在其他方面表现相同。有一个父模型,但它仅用于规范化目的,Web 用户永远不需要知道它。就应用程序而言,存在服务类型以及这些类型下的特定服务。所以基本上我想要这样的 URL:
http://myapp/services # <- Lists all service types
http://myapp/restaurants # <- Lists all restaurant-type services
http://myapp/restaurants/foo # <- Lists a specific restaurant (using friendly_id gem)
http://myapp/retailers # <- Lists all retailer-type services
http://myapp/retailers/bar # <- Lists a specific retailer
所以我创建了一个像这样的路由模式:
controller :services, :via => [:get] do
match '/services' => :index
match '/:service_type' => :service_index, :as => 'service_type', :constraints => { :service_type => Regexp.new(Service::SERVICE_TYPES.values.map{|s| Regexp.escape(s.pluralize) }.join('|')) }
match '/:service_type/:id' => :show, :as => 'service', :constraints => { :service_type => Regexp.new(Service::SERVICE_TYPES.values.map{|s| Regexp.escape(s.pluralize) }.join('|')) }
end
这让我明白了
services GET /services(.:format) {:controller=>"services", :action=>"index"}
service_type GET /:service_type(.:format) {:service_type=>/restaurants|retailers/, :controller=>"services", :action=>"service_index"}
service GET /:service_type/:id(.:format) {:service_type=>/restaurants|retailers/, :controller=>"services", :action=>"show"}
控制器被定义为
class ServicesController < ApplicationController
def index
@service_types = Service::SERVICE_TYPES.values
@page_title = "Services"
end
def service_index
@service_type = params[:service_type]
@domestic = Service.send(@service_type).domestic
@international = Service.send(@service_type).international
@page_title = @service_type.capitalize
end
def show
@service = Service.find(params[:id])
@page_title = "Services - #{@service.name}"
end
end
当我在浏览器中测试它时,这一切都按预期工作。但是当我尝试在 Rspec2 中运行集成测试时,我遇到了一些非常意外的行为。
require 'spec_helper'
describe ServicesController do
describe "GET 'index'" do
it "should be successful" do
get :index
response.should be_success
end
it "should have the right title" do
get :index
response.should have_selector(
"title",
:content => "#{@base_title}Services"
)
end
it "should have a link to each service" do
get :index
Service::SERVICE_TYPES.values.each do |service_type|
response.should have_selector("a", :href => service_type_path(service_type.pluralize),
:content => service_type.pluralize)
end
end
end
describe "GET 'service_index'" do
Service::SERVICE_TYPES.values.each do |service_type|
context service_type.pluralize do
it "should be successful" do
get :service_index, :service_type => service_type.pluralize
response.should be_success
end
it "should have the right title" do
get :service_index, :service_type => service_type.pluralize
response.should have_selector(
"title",
:content => "#{@base_title}#{service_type.pluralize.capitalize}"
)
end
it "should have a link to each service" do
get :service_index, :service_type => service_type.pluralize
Service.send(service_type.pluralize).each do |service|
response.should have_selector("a", :href => service_path(service_type.pluralize, service),
:content => service.name)
end
end
end
end
end
describe "GET 'show'" do
it "should be successful" do
get 'show'
response.should be_success
end
end
end
get
操作似乎运行成功,因为 “应该成功”
测试全部通过,但其他操作失败,因为它无法在页。奇怪的是,返回的 HTML 转储似乎不是来自我的应用程序。
1) ServicesController GET 'index' should have the right title
Failure/Error: response.should have_selector(
expected following output to contain a <title>Services</title> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# ./spec/controllers/services_controller_spec.rb:12:in `block (3 levels) in <top (required)>'
2) ServicesController GET 'index' should have a link to each service
Failure/Error: response.should have_selector("a", :href => service_type_path(service_type.pluralize),
expected following output to contain a <a href='/restaurants'>Restaurants</a> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# ./spec/controllers/services_controller_spec.rb:21:in `block (4 levels) in <top (required)>'
# ./spec/controllers/services_controller_spec.rb:20:in `each'
# ./spec/controllers/services_controller_spec.rb:20:in `block (3 levels) in <top (required)>'
3) ServicesController GET 'service_index' restaurants should have the right title
Failure/Error: response.should have_selector(
expected following output to contain a <title>Restaurants</title> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# ./spec/controllers/services_controller_spec.rb:37:in `block (5 levels) in <top (required)>'
4) ServicesController GET 'service_index' restaurants should have a link to each service
Failure/Error: response.should have_selector("a", :href => service_path(service_type.pluralize, service),
expected following output to contain a <a href='/restaurants/foo'>Foo</a> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# ./spec/controllers/services_controller_spec.rb:46:in `block (6 levels) in <top (required)>'
# ./spec/controllers/services_controller_spec.rb:45:in `block (5 levels) in <top (required)>'
如果这确实是一个失败,我期望看到的是我的 HTML 应用程序模板的完整转储,该模板以 HTML 5 标记。相反,我只得到标记为 HTML 4 的页面的文档类型。
任何想法是什么会导致这样的情况吗?
作为次要问题,我无法找到任何方法来打开 Webrat 中的日志记录以查看实际发生的 HTTP 活动。我怎样才能做到这一点?
I have a services model defined as such:
class Service < ActiveRecord::Base
attr_accessible :service_type #, ...
SERVICE_TYPES = {
:restaurant => "restaurant",
:retailer => "retailer"
}
SERVICE_TYPES.values.each do |method|
define_method method.pluralize.to_sym do
where(:service_type => method)
end
end
def domestic
where(:country => 'USA')
end
def international
where("country != 'USA'")
end
end
I decided to not use a traditional STI pattern for the different services because they will all have the same attributes and otherwise behave identically. There is a parent model, but it is used only for normalization purposes and the web user never needs to know about it. As far as the application goes, there are service types, and specific services under those. So basically I want URLs like this:
http://myapp/services # <- Lists all service types
http://myapp/restaurants # <- Lists all restaurant-type services
http://myapp/restaurants/foo # <- Lists a specific restaurant (using friendly_id gem)
http://myapp/retailers # <- Lists all retailer-type services
http://myapp/retailers/bar # <- Lists a specific retailer
So I created a routing pattern like so:
controller :services, :via => [:get] do
match '/services' => :index
match '/:service_type' => :service_index, :as => 'service_type', :constraints => { :service_type => Regexp.new(Service::SERVICE_TYPES.values.map{|s| Regexp.escape(s.pluralize) }.join('|')) }
match '/:service_type/:id' => :show, :as => 'service', :constraints => { :service_type => Regexp.new(Service::SERVICE_TYPES.values.map{|s| Regexp.escape(s.pluralize) }.join('|')) }
end
Which gets me
services GET /services(.:format) {:controller=>"services", :action=>"index"}
service_type GET /:service_type(.:format) {:service_type=>/restaurants|retailers/, :controller=>"services", :action=>"service_index"}
service GET /:service_type/:id(.:format) {:service_type=>/restaurants|retailers/, :controller=>"services", :action=>"show"}
And the controller is defined as
class ServicesController < ApplicationController
def index
@service_types = Service::SERVICE_TYPES.values
@page_title = "Services"
end
def service_index
@service_type = params[:service_type]
@domestic = Service.send(@service_type).domestic
@international = Service.send(@service_type).international
@page_title = @service_type.capitalize
end
def show
@service = Service.find(params[:id])
@page_title = "Services - #{@service.name}"
end
end
This all works as expected when I test it in the browser. But when I try to run an integration test in Rspec2 I'm getting some really unexpected behavior.
require 'spec_helper'
describe ServicesController do
describe "GET 'index'" do
it "should be successful" do
get :index
response.should be_success
end
it "should have the right title" do
get :index
response.should have_selector(
"title",
:content => "#{@base_title}Services"
)
end
it "should have a link to each service" do
get :index
Service::SERVICE_TYPES.values.each do |service_type|
response.should have_selector("a", :href => service_type_path(service_type.pluralize),
:content => service_type.pluralize)
end
end
end
describe "GET 'service_index'" do
Service::SERVICE_TYPES.values.each do |service_type|
context service_type.pluralize do
it "should be successful" do
get :service_index, :service_type => service_type.pluralize
response.should be_success
end
it "should have the right title" do
get :service_index, :service_type => service_type.pluralize
response.should have_selector(
"title",
:content => "#{@base_title}#{service_type.pluralize.capitalize}"
)
end
it "should have a link to each service" do
get :service_index, :service_type => service_type.pluralize
Service.send(service_type.pluralize).each do |service|
response.should have_selector("a", :href => service_path(service_type.pluralize, service),
:content => service.name)
end
end
end
end
end
describe "GET 'show'" do
it "should be successful" do
get 'show'
response.should be_success
end
end
end
The get
action appears to run successfully because the "should be successful"
tests all pass, but the others fail because it can't find the proper selector(s) on the page. The odd thing is that the dump of HTML that is returned doesn't appear to come from my app.
1) ServicesController GET 'index' should have the right title
Failure/Error: response.should have_selector(
expected following output to contain a <title>Services</title> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# ./spec/controllers/services_controller_spec.rb:12:in `block (3 levels) in <top (required)>'
2) ServicesController GET 'index' should have a link to each service
Failure/Error: response.should have_selector("a", :href => service_type_path(service_type.pluralize),
expected following output to contain a <a href='/restaurants'>Restaurants</a> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# ./spec/controllers/services_controller_spec.rb:21:in `block (4 levels) in <top (required)>'
# ./spec/controllers/services_controller_spec.rb:20:in `each'
# ./spec/controllers/services_controller_spec.rb:20:in `block (3 levels) in <top (required)>'
3) ServicesController GET 'service_index' restaurants should have the right title
Failure/Error: response.should have_selector(
expected following output to contain a <title>Restaurants</title> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# ./spec/controllers/services_controller_spec.rb:37:in `block (5 levels) in <top (required)>'
4) ServicesController GET 'service_index' restaurants should have a link to each service
Failure/Error: response.should have_selector("a", :href => service_path(service_type.pluralize, service),
expected following output to contain a <a href='/restaurants/foo'>Foo</a> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# ./spec/controllers/services_controller_spec.rb:46:in `block (6 levels) in <top (required)>'
# ./spec/controllers/services_controller_spec.rb:45:in `block (5 levels) in <top (required)>'
What I would expect to see if this was indeed a failure would be the complete dump of my HTML application template which is marked up in HTML 5. Instead I'm getting only the doctype of a page marked up as HTML 4.
Any ideas what would cause that?
As a secondary issue, I can't figure out any way to turn on logging in Webrat to see what HTTP activity is actually happening. How can I do that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
是的,没关系。我是个白痴,忘记将
render_views
放入我的测试中这就是为什么它没有渲染视图。Yeah, never mind. I'm an idiot and forgot to put
render_views
inside my test which is why it wasn't rendering the view.