Ruby RSpec Net:HTTP - 如何在模拟响应时测试请求负载是否符合预期

Ruby RSpec Net:HTTP - How to test request payload is as expected while mocking a response

我是一个很!!新的 ruby 和 Rspec 用户正在努力理解如何在模拟来自外部 API 的响应时对 API 请求是否设置了预期的请求负载进行单元测试。我已经使用 Net:HTTP 实现了 API 请求来限制依赖性。

方法正在测试

 def lint (url, path, headers={ "Content-Type" => "application/json" }, timeout=10)
            if yamlContent = GitLab::Lint::Client::YamlFile.new(path).get_json_content()
            
              uri = URI.parse(url)

              req = Net::HTTP::Post.new(uri, headers)
              req.body = { content: yamlContent }.to_json
              
              https = Net::HTTP.new(uri.host, uri.port)
              https.use_ssl = true
              https.verify_mode = OpenSSL::SSL::VERIFY_PEER
              
              response = https.request(req)
          
              case response
                  when Net::HTTPSuccess
                      puts "Linting request successful"
                      return JSON.parse(response.body)
                  when Net::HTTPUnauthorized
                      abort("#{response.message}: invalid token in api request?")
                  when Net::HTTPServerError
                      abort('error' => "#{response.message}: server error, try again later?")
                  when Net::HTTPBadRequest
                      puts "Bad request..." + req.body
                      abort("#{response.message}: bad api request?")
                  when Net::HTTPNotFound
                      abort("#{response.message}: api request not found?")
                  else
                      puts "Failed validation\nJSON payload :: #{req.body}\nHTTP Response: #{response.message}"
                      abort("#{response.message}: failed api request?")
              end
            else
              abort("\nLint request failed, problem encountered reading yaml file")
            end
end

RSpec 测试

require "gitlab/lint/client/api"

RSpec.describe Gitlab::Lint::Client::Api do
    
    describe "#initialize" do
        it "initialises" do          
            api = Gitlab::Lint::Client::Api.new
            expect(api).to be_instance_of(Gitlab::Lint::Client::Api)
        end
    end

    describe "#lint" do
        before(:each) do
            @response = instance_double(Net::HTTPSuccess, body: @response_body, message: 'OK')
            @response_body = { 'status' => 'valid', 'errors' => [] }.to_json
            
            @request_mock = instance_double(Net::HTTP::Post)
            allow(@request_mock).to receive(:[]=)
            allow(@request_mock).to receive(:body=)
            allow(Net::HTTP::Post).to receive(:new).and_return(@request_mock)

            @http_client_mock = instance_double(Net::HTTP)
            allow(@http_client_mock).to receive(:use_ssl=)
            allow(@http_client_mock).to receive(:verify_mode=)
            allow(@http_client_mock).to receive(:request)
            allow(Net::HTTP).to receive(:new).and_return(@http_client_mock)
            allow(@http_client_mock).to receive(:request).with(@request_mock).and_return(@response)
                  
            @endpoint_url = 'http://gitlab.com'

            @fileName='test.yml'
            
            allow(File).to receive(:exist?).with(@fileName).and_return(true)
            allow(File).to receive(:readable?).with(@fileName).and_return(true)
            allow(YAML).to receive(:load_file).with(@fileName).and_return("image: ruby:latest")
        end

        it "lints successfully" do
           
            # for a valid case we want:
            # - test that the request body was set with content as expected
            # - simulate the response to be { status: "valid", "errors": []}

            api = Gitlab::Lint::Client::Api.new
            api.lint(@endpoint_url, @fileName)

            expect(@request_mock.body).to have_received({ content: {'image' => 'ruby:latest'} }.to_json)
        end
    end
end

运行 测试给出以下错误输出:

Gitlab::Lint::Client::Api
  #initialize
    initialises
  #lint
OK: failed api request? # this output signifies that the case structure has not recognised the response as a HTTPSuccess instance

在我的 lint 测试方法的案例结构中,响应未被视为 Net::HTTPSuccess 的实例。如何模拟 Net::HTTPSuccess 实例?

一种流行的方法称为 VCR。您可以在项目网站上找到大量文档和 RailsCast。基本上,它是这样工作的:

  • 您将 VCR 设置为“记录模式”。
  • 您向真实后端发出请求。 VCR 记录请求和响应。
  • 您将 VCR 设置为“回放”模式。
  • 当您 运行 测试时,您可以使用 VCR 对请求和响应做出断言(换句话说,它符合您的期望)。

这是一种验证 HTTP 请求是否完全按照您的要求执行的可靠方法。