[RUBY] Umgang mit dem Ereignis, dass Committee :: InvalidRequest während des Rspec-Datei-Upload-Tests im Committee auftritt

Der auftretende Fehler

     Committee::InvalidRequest:
       #/paths/~1contracts/post/requestBody/content/multipart~1form-data/schema/properties/original_file expected string, but received ActionDispatch::Http::UploadedFile: #<ActionDispatch::Http::UploadedFile:0x00007fa77e1f36a0>

Was ich machen will; was ich vorhabe zu tun

Es definiert eine API, die Datei-Uploads im Format "Multipart / Formulardaten" empfängt. Die API basiert auf den Spezifikationen von OpenAPI 3.0, zum Beispiel:

requestBody:
  original_file:
    image/png:
      schema:
        type: string
        format: binary

Es befindet sich auch in der Dokumentation zu Swagger.

Ich möchte eine Rspec für diese API mit dem Juwel "Committee" schreiben.

Inhalt testen

some_controller_spec.rb


#Formularparameter
let(:file_upload_form) {
  {
    article_id: 1_000,
    name: 'This is good article',
    # set real existing file
    original_file: fixture_file_upload(
      Rails.root.join('sample_files/sample.docx'),
      'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
    )
  }
}

Die als Anforderung verwendeten Parameter sind wie oben definiert, und die hochzuladende Datei ist die zum Testen vorbereitete Docx-Datei. Dies wird wie folgt POSTED und das API-Format wird durch die Methode assert_schema_conform überprüft.

some_controller_spec.rb


it 'uploads file' do
  post api_v1_images_path,
         headers: authenticated_header(user),
         params: file_upload_form

  expect(response).to have_http_status(:success)
  assert_schema_conform
end

Fehlerursache

Die API-Anforderungsspezifikation lautet "type: string", aber im Test wird das Objekt "ActionDispatch" festgelegt, sodass die Fehlermeldung angezeigt wird, dass es nicht den Erwartungen entspricht. Da es sich jedoch um einen Datei-Upload-Test handelt, funktioniert die interne Verarbeitung nicht mit String, sodass sie nicht geändert werden kann. Das war ein Problem.

Lage

Wo der Fehler aufgetreten ist

Der Fehler tritt im folgenden "OpenAPIParser" -Prozess auf. [lib/openapi_parser/schema_validators/string_validator.rb#L11] (https://github.com/ota42y/openapi_parser/blob/44c640cc103bbbb9e8029e41a8889e8fd9350902/lib/openapi_parser/schema_validators/string_validator.rb#L11)

lib/openapi_parser/schema_validators/string_validator.rb



    def coerce_and_validate(value, schema, **_keyword_args)
      return OpenAPIParser::ValidateError.build_error_result(value, schema) unless value.kind_of?(String)

      # ...Unten weggelassen...

    end

Es wird einfach geprüft, ob "value" eine "String" -Klasse ist, und wenn es sich nicht um "String" handelt, handelt es sich um einen Fehler. Da dies ein Objekt von "ActionDispatch" ist, ist "value.kind_of? (String)" dieses Mal falsch und es tritt ein Fehler auf.

Selbst wenn es "type: string" ist, wenn es "format: binary" ist, erlaubt es andere als die "String" -Klasse.

Im Fall von format: binay wie einer Datei können Sie die Bedingungen ändern, um den Fehler nicht auszulösen. Erstellen Sie dafür einen Patch. Erstellen Sie ein beliebiges Modul, das die entsprechende Methode "coerce_and_validate (value, schema, ** _keyword_args)" als Stapel definiert.

module StringValidatorPatch
  def coerce_and_validate(value, schema, **keyword_args)
    #Ändern Sie diesen Prozess
    # https://github.com/ota42y/openapi_parser/blob/61874f0190a86c09bdfb78de5f51cfb6ae16068b/lib/openapi_parser/schema_validators/string_validator.rb#L11
    if !value.is_a?(String) && schema.format != 'binary'
      return OpenAPIParser::ValidateError.build_error_result(value, schema)
    end
    # ---Bisher

    value, err = check_enum_include(value, schema)
    return [nil, err] if err

    value, err = pattern_validate(value, schema)
    return [nil, err] if err

    unless @datetime_coerce_class.nil?
      value, err = coerce_date_time(value, schema)
      return [nil, err] if err
    end

    value, err = validate_max_min_length(value, schema)
    return [nil, err] if err

    value, err = validate_email_format(value, schema)
    return [nil, err] if err

    value, err = validate_uuid_format(value, schema)
    return [nil, err] if err

    [value, nil]
  end
end

Definieren Sie auf diese Weise ein Modul, das nur die Methode neu definiert, die Sie ändern möchten. Öffnen Sie die Klasse, die Sie für dieses Modul patchen möchten, erneut die OpenAPIParser :: SchemaValidator :: StringValidator-Klasse, und überschreiben Sie die Methode mit Module # prepend. Modul # Referenz voranstellen

class OpenAPIParser::SchemaValidator::StringValidator
  prepend StringValidatorPatch
end

Dadurch wird der Fehler "Committee :: InvalidRequest" beseitigt

Auswirkungen minimieren

Sie können den Fehler "Committee :: InvalidRequest" vermeiden, indem Sie einen Patch anwenden. Das Anwenden eines Patches in einem globalen Bereich wirkt sich jedoch auf das Ganze aus. Ich möchte, dass diese Änderung nur für Tests mit Datei-Uploads wirksam wird. Erwägen Sie daher, es in "context'some context'do ... end" zu definieren, damit es nur im erforderlichen Kontext von Rspec wiedergegeben wird.

some_controller_spec.rb


RSpec.describe SomeController, type: :request do
  context 'some context' do

    #Wenden Sie Patches im Kontext an
    module StringValidatorPatch
      def coerce_and_validate(value, schema, **keyword_args)
        if !value.is_a?(String) && schema.format != 'binary'
          return OpenAPIParser::ValidateError.build_error_result(value, schema)
        end
        # (Folgendes wird weggelassen)
      end
    end

    class OpenAPIParser::SchemaValidator::StringValidator
      prepend StringValidatorPatch
    end
    #Patch bisher

    it 'uploads file' do
      post api_v1_images_path,
             headers: authenticated_header(user),
             params: file_upload_form

      expect(response).to have_http_status(:success)
      assert_schema_conform
    end
  end
end

Da der Bereich des Blocks jedoch weder die Konstanten trennt noch den Namespace festlegt, möchten wir die Verarbeitung wie die Klassendefinition im Block vermeiden. Rubocops Lint / ConstantDefinitionInBlock bleibt ebenfalls hängen. Wenn Sie eine ähnliche Konstante in Rspec definieren möchten, verwenden Sie stub_const (), um sie zu definieren.

Verwenden Sie stub_const (), um dort zu patchen, wo Sie es brauchen

Verwenden Sie Class.new, um eine Klasse ohne das Schlüsselwort "class" erneut zu öffnen .. Sie können eine Klasse auch definieren, indem Sie einen Block übergeben

Foo = Class.new {|c|
  def hello; 'hello'; end
}

puts Foo.new.hello # => 'hello'

Verwenden Sie diese Option, um eine gepatchte Klasse zu definieren. Speichern Sie das Modul "StringValidatorPatch" für den Patch im Verzeichnis "spec / support" als "string_validator_patch.rb", damit er geladen werden kann.

patched = Class.new(OpenAPIParser::SchemaValidator::StringValidator) do |klass|
  klass.prepend StringValidatorPatch
end

stub_const('OpenAPIParser::SchemaValidator::StringValidator', patched)

Wenn Sie eine Klasse an das Argument "Class.new ()" übergeben, wird sie als übergeordnete Klasse behandelt. Im obigen Fall ist "gepatcht" eine untergeordnete Klasse von "OpenAPIParser :: SchemaValidator :: StringValidator". Wenn Sie eine Konstante mit "stub_const ()" definieren, können Sie die gepatchte Klasse verwenden.

Implementieren Sie diesen Prozess nach Bedarf mit "vor" oder "lassen".

Zusammenfassung

--Patch die Validator-Klasse, um den Fehler Committee :: InvalidRequest zu löschen

spec/support/string_validator_patch.rb


module StringValidatorPatch
  def coerce_and_validate(value, schema, **keyword_args)
    #Ändern Sie diesen Prozess
    # https://github.com/ota42y/openapi_parser/blob/61874f0190a86c09bdfb78de5f51cfb6ae16068b/lib/openapi_parser/schema_validators/string_validator.rb#L11
    if !value.is_a?(String) && schema.format != 'binary'
      return OpenAPIParser::ValidateError.build_error_result(value, schema)
    end
    # ---Bisher

    value, err = check_enum_include(value, schema)
    return [nil, err] if err

    value, err = pattern_validate(value, schema)
    return [nil, err] if err

    unless @datetime_coerce_class.nil?
      value, err = coerce_date_time(value, schema)
      return [nil, err] if err
    end

    value, err = validate_max_min_length(value, schema)
    return [nil, err] if err

    value, err = validate_email_format(value, schema)
    return [nil, err] if err

    value, err = validate_uuid_format(value, schema)
    return [nil, err] if err

    [value, nil]
  end
end

some_controller_spec.rb


RSpec.describe SomeController, type: :request do
  context 'some context' do
    let(:file_upload_form) {
      {
        article_id: 1_000,
        name: 'This is good article',
        original_file: fixture_file_upload(
          Rails.root.join('sample_files/sample.docx'),
          'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
        )
      }
    }

    before do
      #Wenden Sie Patches im Kontext an
      patched = Class.new(OpenAPIParser::SchemaValidator::StringValidator) do |klass|
        klass.prepend StringValidatorPatch
      end
      stub_const('OpenAPIParser::SchemaValidator::StringValidator', patched)
    end

    it 'uploads file' do
      post api_v1_images_path,
           headers: authenticated_header(user),
           params: file_upload_form

      expect(response).to have_http_status(:success)
      assert_schema_conform
    end
  end
end

Recommended Posts

Umgang mit dem Ereignis, dass Committee :: InvalidRequest während des Rspec-Datei-Upload-Tests im Committee auftritt
So testen Sie den Bildschirm zum Hochladen von Dateien mit Spring + Selenium
So erreichen Sie das Hochladen von Dateien mit Feign
So testen Sie Interrupts während Thread.sleep mit JUnit
So beheben Sie Fehler, die beim Integrationstest "Ruby on Rails" auftreten
Speichern von Dateien mit der angegebenen Erweiterung unter dem in Java angegebenen Verzeichnis in der Liste
So debuggen Sie die generierte JAR-Datei mit Eclipse
Umgang mit dem Fehler yaml.scanner.ScannerError: Beim Scannen nach dem nächsten Token, das beim Erstellen einer Rails-Umgebung mit Docker angezeigt wurde
So löschen Sie das Testbild, nachdem Sie den Rspec-Test mit CarrierWave ausgeführt haben
Wie gehe ich mit dem Typ um, den ich 2 Jahre lang über das Schreiben eines Java-Programms nachgedacht habe?
[Rails / RSpec] Der Umgang mit Elementen weist einen Größenfehler von Null auf
So erstellen Sie eine JAR-Datei ohne Abhängigkeiten in Maven
So realisieren Sie mit TERASOLUNA 5.x (= Spring MVC) das Hochladen großer Dateien
So ermitteln Sie die Länge einer Audiodatei mit Java
So erzielen Sie mit Rest Template of Spring einen großen Datei-Upload
So interagieren Sie mit einem Server, der die App nicht zum Absturz bringt
So testen Sie eine private Methode und verspotten sie teilweise in Java
[Rails] So erhalten Sie die aktuell mit devise angemeldeten Benutzerinformationen
[Rails] So wenden Sie das in der Hauptanwendung verwendete CSS mit Administrate an
So starten Sie einen Docker-Container mit einem in einer Batchdatei bereitgestellten Volume
[Java] Verwendung der File-Klasse
So filtern Sie den JUnit-Test in Gradle
[Hinweis] Erste Schritte mit Rspec
So fügen Sie eine JAR-Datei in ScalaIDE hinzu
So erreichen Sie den Dateidownload mit Feign
So testen Sie den privaten Bereich mit JUnit
Der Umgang mit dem Vorkompilieren von Assets ist fehlgeschlagen.
[Rails] Lesen der vom Bildschirm hochgeladenen XML-Datei im Hash-Typ
So erhalten Sie die ID eines Benutzers, der sich in Swift bei Firebase authentifiziert hat
[Schienen] So registrieren Sie mehrere Datensätze in der Zwischentabelle mit einer Zuordnung von vielen zu vielen
[Rails] So bedienen Sie die in der Hauptanwendung verwendete Hilfsmethode mit Administrate
Festlegen, wann in junit "Der Konstruktor Empty () ist nicht sichtbar" auftritt
So legen Sie Umgebungsvariablen in der Eigenschaftendatei der Spring-Boot-Anwendung fest
So testen Sie eine Klasse, die application.properties mit SpringBoot verarbeitet (Anfrage: darauf hingewiesen)