【发布时间】:2009-03-01 00:05:41
【问题描述】:
我有一个 Rails 应用程序,它的行为取决于它所访问的域(例如 www.myapp.com 调用的方式与 user.myapp.com 不同)。在生产使用中,这一切正常,但我的测试代码总是看到“www.example.com”的主机名。
有没有一种干净的方式让测试指定它假装访问的主机名?
【问题讨论】:
标签: ruby-on-rails rspec
我有一个 Rails 应用程序,它的行为取决于它所访问的域(例如 www.myapp.com 调用的方式与 user.myapp.com 不同)。在生产使用中,这一切正常,但我的测试代码总是看到“www.example.com”的主机名。
有没有一种干净的方式让测试指定它假装访问的主机名?
【问题讨论】:
标签: ruby-on-rails rspec
我认为这里所有的答案都不完整……列举所有可能的情况:
集成规范(继承自ActionDispatch::IntegrationTest):
host! "my.awesome.host"
请参阅docs,第 5.1 节可用于集成测试的助手。
控制器规格(继承自 ActionController::TestCase)
@request.host = 'my.awesome.host'
参见docs,第 4.4 节 可用的实例变量。
功能规格(通过 Capybara)
Capybara.default_host = "http://my.awesome.host"
# Or to configure domain for route helpers:
default_url_options[:host] = "my.awesome.host"
查看规格(继承自ActionView::TestCase)
@request.host = 'my.awesome.host'
...或通过 RSpec:
controller.request.host = "my.awesome.host"
见rspec-railsview spec docs。
【讨论】:
ActionController::TestCase 切换到 ActionDispatch::IntegrationTest 这个顶部 Integration Specs 对于我们这些使用旧版多租户应用程序的人来说是无价的。这是第一个显示如何将@request.host 轻松转换为旧套件的答案(通过使用host!)。阅读文档并没有引起我的注意,但我们到了,谢谢!
default_url_options[:host] = "my.awesome.host" 去哪儿了?
@request.host = 'user.myapp.com'
【讨论】:
host! 时出现错误。像答案建议的那样设置@request.host虽然有效。
Capybara.app_host = "http://example.com" 为我工作。
在功能规格中,主持人!已被弃用。将这些添加到您的spec_helper.rb:
# Configure Capybara expected host
Capybara.app_host = "http://test.domain"
# Configure actual routes host during test
before(:each) do
default_url_options[:host] = <myhost>
end
在请求规范中,继续使用主机! :
host! "test.domain"
或者在before(:each) 块中重构它,或者在spec_helper.rb 级别为请求规范全局配置它:
RSpec.configure do |config|
config.before(:each, type: :request) do
host! "test.domain"
end
end
【讨论】:
Capybara.app_host 似乎需要包含协议。例如。 "http://test.domain" 而不仅仅是 "test.domain"。
config/environments/test.rb 中定义默认 url 选项不能“正常工作”是我无法理解的。
对于 Rspec 请求规范,请使用 before(:each) { host! 'example.com' }
查看更多信息: https://relishapp.com/rspec/rspec-rails/v/3-6/docs/request-specs/request-spec https://github.com/rspec/rspec-rails/issues/1662#issuecomment-241201056
【讨论】:
我相信您可以修改 HTTP_HOST 或 SERVER_NAME 环境变量来更改发送到路由器的请求:
ENV['SERVER_NAME'] = "user.myapp.com"
在actionpack/lib/action_controller/request.rb 中查看raw_host_with_port。
【讨论】:
要记住的另一件事是确保使用正确的会话实例,以便您可以正确封装 url 助手。
集成测试为您提供默认会话。你可以直接从你的测试中调用all session methods
test "should integrate well" do
https!
get users_path
assert_response :success
end
所有这些帮助程序都使用默认会话实例,如果不更改,则会转到“www.example.com”。如前所述,可以通过执行 host!("my.new.host")
来更改主机如果您使用 open_session 方法创建多个会话,则必须始终使用该实例来调用辅助方法。这将正确封装请求。否则,rails 将调用可能使用不同主机的默认会话实例:
test "should integrate well" do
sess = open_session
sess.host! "my.awesome.host"
sess.get users_url #=> WRONG! will use default session object to build url.
sess.get sess.users_url #=> Correctly invoking url writer from my custom session with new host.
sess.assert_response :success
end
如果您打算使用默认会话对象,那么您还必须更改该主机:
test "should integrate well" do
sess = open_session
sess.host! "my.awesome.host"
host! sess.host #=> Set default session host to my custom session host.
sess.get users_url
end
【讨论】:
@request.host = 'user.myapp.com' 不对。
应该使用host!('user.myapp.com')
【讨论】:
我尝试了@request.host、host! 和post path, args, {'SERVER_NAME' => my_secret_domain} 的许多变体,但都没有成功,无论是作为控制器测试还是功能测试。非常令人恼火,因为许多其他人报告说这些方法取得了成功。
我的解决方案是:
request.headers["SERVER_NAME"] = my_secret_domain
post path, args
我正在运行 ruby 2.1.5p273、rspec 3.1.7 和 Rails 4.2.0
【讨论】:
当时其他答案中建议的方法都不适合我。这有效:
Capybara.configure { |config| config.default_host = "my.domain.com" }
【讨论】:
另一个答案:
request.host = "user.myapp.com"
我知道它类似于正确答案,但请多多包涵。我不喜欢测试中的赋值操作只是为了设置,我更喜欢显式存根。有趣的是,这样的存根不会工作:
allow(request).to receive(:host).and_return("user.myapp.com")
我个人更喜欢存根而不是赋值,这样我得到了两个好处,一个是它将由 rspec 的 verify double 进行验证,第二个是它明确表示这是一个存根,而不是部分的测试练习。
【讨论】: