我有一个 Rails 应用程序,它的行为取决于它访问的域(例如 www.myapp.com 将调用不同的 user.myapp.com)。在生产使用中,这一切正常,但我的测试代码总是看到“www.example.com”的主机名。
有没有一种干净的方式让测试指定它假装访问的主机名?
集成/请求规范(继承自 ActionDispatch::IntegrationTest):宿主! '我的.awesome.host'
请参阅 docs,第 5.1 节可用于集成测试的助手。
或者,在 spec_helper.rb 级别为请求规范全局配置它:
RSpec.configure do |config|
config.before(:each, type: :request) do
host! 'my.awesome.host'
end
end
控制器规格(继承自 ActionController::TestCase)@request.host = 'my.awesome.host'
请参阅 docs,第 4.4 节可用的实例变量。
Feature Specs (through Capybara) Capybara.default_host = 'http://my.awesome.host' # 或者为路由助手配置域:default_url_options[:host] = 'my.awesome.host'
查看规格(继承自 ActionView::TestCase)@request.host = 'my.awesome.host'
...或通过 RSpec:
controller.request.host = 'my.awesome.host'
请参阅 rspec-rails
view spec docs。
@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”。正如已经提到的,主机可以通过做主机来改变!(“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 的验证双重验证,第二个是它明确表示这是一个存根,而不是测试练习的一部分。
不定期副业成功案例分享
ActionController::TestCase
切换到ActionDispatch::IntegrationTest
,这个顶级Integration Specs
对于我们这些使用旧版多租户应用程序的人来说是非常宝贵的。这是第一个展示如何将@request.host
轻松转换为旧套件(通过使用host!
)的答案。阅读文档并没有引起我的注意,但我们到了,谢谢!default_url_options[:host] = "my.awesome.host"
去哪儿了?