70

我有一个 Rails 应用程序,它的行为取决于它访问的域(例如 www.myapp.com 将调用不同的 user.myapp.com)。在生产使用中,这一切正常,但我的测试代码总是看到“www.example.com”的主机名。

有没有一种干净的方式让测试指定它假装访问的主机名?

4

10 回答 10

112

我认为这里所有的答案都不完整......列举所有可能的情况:

  • 集成规范(继承自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"
    

    来自@AminAriana 的回答

  • 查看规格(继承自ActionView::TestCase

    @request.host = 'my.awesome.host'
    

    ...或通过 RSpec:

    controller.request.host = "my.awesome.host"
    

    请参阅rspec-rails 视图规范文档

于 2015-03-13T16:36:58.393 回答
35
@request.host = 'user.myapp.com'
于 2009-03-01T02:33:03.063 回答
26

功能规格

在功能规格中,主机!已被弃用。将这些添加到您的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
于 2015-02-23T21:27:45.043 回答
7

对于 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

于 2018-04-05T20:03:56.570 回答
5

我相信您可以修改HTTP_HOSTorSERVER_NAME环境变量来更改发送到路由器的请求:

ENV['SERVER_NAME'] = "user.myapp.com"

参见actionpack/lib/action_controller/ request.rb raw_host_with_port

于 2009-03-01T02:23:10.217 回答
5

要记住的另一件事是确保使用正确的会话实例,以便您可以正确封装 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 
于 2013-09-24T15:33:59.097 回答
3

@request.host = 'user.myapp.com'是不正确的。应该使用host!('user.myapp.com')

于 2010-06-18T03:29:40.333 回答
1

作为控制器测试和功能测试,我尝试了 , 的许多变体@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

于 2015-04-08T20:38:53.480 回答
1

当时其他答案中建议的方法都不适合我。这有效:

Capybara.configure { |config| config.default_host = "my.domain.com" }
于 2018-02-19T11:43:20.097 回答
0

还有一个答案:

request.host = "user.myapp.com"

我知道它类似于正确答案,但请多多包涵。我不喜欢测试中的赋值操作只是为了设置,我更喜欢显式存根。有趣的是,这样的存根是行不通的:

allow(request).to receive(:host).and_return("user.myapp.com")

我个人更喜欢存根而不是赋值,这样我可以获得两个好处,一个是它将由rspec 的 verify double进行验证,第二个是它明确表示这是一个存根,而不是测试练习的一部分。

于 2017-04-06T07:07:28.900 回答