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>
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.
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
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
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.
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
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.
stub_const ()
, um dort zu patchen, wo Sie es brauchenVerwenden 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".
--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