【问题标题】:How to make ActiveResource integration test case?如何制作 ActiveResource 集成测试用例?
【发布时间】:2018-10-10 11:49:38
【问题描述】:

我正在使用 Rails 开发一个内部 API,我正在考虑使用 ActiceResource 来访问它。我想使用 ActiveResource 制作集成测试用例(即向测试环境中的控制器发出 http 请求),但不知道如何设置测试用例。

在正常的集成测试用例中,您使用 get/post 方法向您自己的应用发送请求。不知何故,我应该告诉 ActiceResource 连接到我的应用程序,而不是建立真正的 http 连接。

我看到的所有 ActiveResource 测试示例都使用模拟。我想避免这种情况,而是针对我的控制器代码运行我的测试。我正在使用 Rails 5 和 Minitest。

下面是显然不起作用的测试代码。如果我尝试运行它,它会报错:

require 'test_helper'

module MyApp
  class User < ActiveResource::Base
    self.site = 'http://www.example.com'
  end
end

class UserFlowsTest < ActionDispatch::IntegrationTest
  test "should get index" do
    users = MyApp::User.all

    assert_response :success
  end
end


▶ rails test test/integration/user_flows_test.rb
NoMethodError: undefined method `response_code' for nil:NilClass
    actionpack (5.2.1) lib/action_dispatch/testing/assertions/response.rb:81:in `generate_response_message'
    actionpack (5.2.1) lib/action_dispatch/testing/assertions/response.rb:31:in `assert_response'
    test/integration/user_flows_test.rb:13:in `block in <class:UserFlowsTest>'

【问题讨论】:

    标签: ruby-on-rails activeresource


    【解决方案1】:

    我找到了一种方法来做到这一点。这是一个 hack,但似乎工作得很好。

    在 IntegrationTest Rails 中定义了 get/post/etc 帮助方法,然后您可以在测试用例中使用这些方法来连接您的 Rails 应用程序。为了使 ActiveResource 使用辅助方法而不是发出真正的 HTTP 请求,我修改了 AR 请求方法。我使用全局变量来发送当前测试用例并访问辅助方法。

    # Include this in test_helper.rb into ActiveSupport::TestCase class
    module ActiveResourceMonkeyPatching
      module ::ActiveResource
        # We need to monkey patch AR:Connection to use IntegrtionTest helper
        # methods (get, post, ...) instead of Net:Http
        class Connection
          private
    
          # Makes a request to the remote service.
          def request(method, path, *arguments)
            result = ActiveSupport::Notifications
                    .instrument('request.active_resource') do |payload|
              payload[:method] = method
              payload[:request_uri] =
                "#{site.scheme}://#{site.host}:#{site.port}#{path}"
              payload[:result] =
                $test.send(method,
                          path,
                          { params: arguments.first, headers: arguments.last }) &&
                $test.response
            end
            handle_response(result)
          rescue Timeout::Error => e
            raise TimeoutError.new(e.message)
          rescue OpenSSL::SSL::SSLError => e
            raise SSLError.new(e.message)
          end
        end
    
        # Lets also predefine site so we don't need to configure those in test cases
        class Base
          self.site = 'http://www.example.com'
        end
      end
    
      # We also monkey patch IntegrationTest to set the '$test' global variance which is
      # needed in ActiveResource
      class ActionDispatch::IntegrationTest
        def setup
          $test = self
          super
        end
      end
    end
    

    自从我开始打猴子补丁以来,我还添加了一些更多来传递全局变量并设置虚拟site 属性。实际的测试用例很简单,见下文。由于我们将其作为普通的 IntergrationTest 运行,因此用户模型中的所有装置都照常加载。

    require 'test_helper'
    
    module MyApp
      class User < ActiveResource::Base
      end
    end
    
    class UserFlowsTest < ActionDispatch::IntegrationTest
      test "should get index" do
        users = MyApp::User.all
    
        assert_response :success
      end
    end
    

    这是一个 hack :) 使用猴子补丁意味着上述解决方案适用于当前版本的 Rails 和 ActiveResource,并且在更新时会失败。如果有人找到解决此问题的其他方法,我很想知道。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多