我有一个 Rails 应用程序,它的行为取决于它访问的域(例如 www.myapp.com 将调用不同的 user.myapp.com)。在生产使用中,这一切正常,但我的测试代码总是看到“www.example.com”的主机名。
有没有一种干净的方式让测试指定它假装访问的主机名?
我有一个 Rails 应用程序,它的行为取决于它访问的域(例如 www.myapp.com 将调用不同的 user.myapp.com)。在生产使用中,这一切正常,但我的测试代码总是看到“www.example.com”的主机名。
有没有一种干净的方式让测试指定它假装访问的主机名?
我认为这里所有的答案都不完整......列举所有可能的情况:
集成规范(继承自ActionDispatch::IntegrationTest
):
host! "my.awesome.host"
请参阅文档,第 5.1 节可用于集成测试的帮助程序。
控制器规格(继承自ActionController::TestCase
)
@request.host = 'my.awesome.host'
请参阅文档,第 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-rails
视图规范文档。
@request.host = 'user.myapp.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
对于 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
orSERVER_NAME
环境变量来更改发送到路由器的请求:
ENV['SERVER_NAME'] = "user.myapp.com"
参见actionpack/lib/action_controller/ request.rb raw_host_with_port
。
要记住的另一件事是确保使用正确的会话实例,以便您可以正确封装 url 助手。
集成测试为您提供默认会话。您可以直接从测试中调用所有会话方法
test "should integrate well" do
https!
get users_path
assert_response :success
end
所有这些助手都使用默认会话实例,如果不更改,则转到“www.example.com”。正如已经提到的,主机可以通过做主机来改变!(“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进行验证,第二个是它明确表示这是一个存根,而不是测试练习的一部分。