Estoy intentando escribir una prueba bastante sencilla en un objeto de servicio que maneja un error. Rails versión 5.2 y Rspec 3.8.
aplicación/servicios/aplicación_servicio.rb
class ApplicationService
def self.call(*args, &block)
new(*args, &block).call
end
end
aplicación/servicios/basic_objects/create_paid.rb
module BasicObjects
class CreatePayment < ApplicationService
def initialize(args)
@transaction_id = args[:transaction_id]
end
def call
transaction = Transaction.find(@transaction_id)
payment = Payment.new(transaction: transaction)
payment.save
rescue CustomError => e
if /waiting/i === e.message
puts "Ignoring exception \"#{e.message}\" to prevent retry"
else
raise e
end
end
end
Aquí está la prueba
describe BasicObjects::CreatePayment, type: :model do
describe '#call' do
let(:params) { { transaction_id: "xyz" } }
context 'when there is a rescued error' do
before do
allow_any_instance_of(Payment)
.to receive(:save)
.and_raise(CustomError, "waiting")
end
it 'does not raise an error' do
expect { described_class.call(params) }.not_to raise_error
end
end
end
end
Y responde con este error:
No se esperaba ninguna excepción, obtuve #<ArgumentError: número incorrecto de argumentos (dado 1, esperado 0)
Pero si elimino los parámetros y en su lugar espero(described_class.call).not_to rise_error
Me sale error por no enviar el argumento
<BasicObjects::CreatePayment (class)> received :call with unexpected arguments
expected: ({:transaction_id=>"xyz"})
got: (no args)
Entonces, elimino with(params) de la declaración de permiso
context 'when there is a rescued error' do
before do
allow(described_class).to receive(:call).and_raise(CustomError, "waiting")
end
it 'does not raise an error' do
expect(described_class.call).not_to raise_error
end
end
Y obtengo
ArgumentError:
wrong number of arguments (given 1, expected 0)
Cualquier ayuda es muy apreciada
ACTUALIZACIÓN
He ajustado la llamada anterior para generar el error en una línea de la clase, en lugar der que simplemente llamar a la clase misma. Sin embargo, sigo recibiendo el mismo error: no se esperaba ninguna excepción, obtuve #<ArgumentError: número incorrecto de argumentos (dado 1, se esperaba 0)>
1
¿Estás reemplazando la llamada al método de la clase, no la de la instancia?
Cassandra S.
27/03/2021 a las 18:54
Lo llamo como se llama en la aplicación. ¿De qué otra manera lo hago?
-Carl
27/03/2021 a las 19:06
------------------------------------
Vaya, este fue un viaje confuso. Muy bien, recapitulemos:
Cuando escribes enable(described_class).toceived(:call).and_raise(...), estás diciendo que este método:
class ApplicationService
def self.call(*args, &block)
new(*args, &block).call
end
end
debería generar el error. Cuando pruebas tu código localmente, eso es lo que realmente sucede.
Dado que la llamada de clase no es lo que se está probando, te sugiero que la pruebes así:
it 'does not raise an error' do
dbl = class_double(Transaction)
allow(dbl).to receive(:find).and_raise(CustomError, 'waiting')
expect { described_class.new(params).call }.not_to raise_error
end
En realidad no puedes cortar elllamada al método de instancia, porque al hacerlo también eliminarás el rescate real que estás probando.
3
Gracias. Agregué ApplicationService a la publicación anterior, que implementa una llamada a un método de clase. Espero que eso aclare
-Carl
27/03/2021 a las 20:02
Lo siento, así es como espreguntó en el poste. En realidad, está todo en una sola línea.
-Carl
27/03/2021 a las 20:34
Muy bien, actualicé mi respuesta por última vez. Esto fue muy confuso, jajaja.
Cassandra S.
27/03/2021 a las 20:55
------------------------------------
Me encontré con un problema similar y apareció el mensaje <ArgumentError: número incorrecto de argumentos (dado 1, esperado 0)> fue muy engañoso y confuso.
Dado su ejemplo, el problemaEs probable que el método de inicialización de su clase CustomError tome 0 argumento y esté pasando el método de "espera" cadena como parte de tu simulacro, es decir. permitir_cualquier_instancia_de(Pago).to recibir(:guardar).and_raise(CustomError, "esperando").
El mensaje de error en realidad se queja de que está pasando una cantidad incorrecta de argumentos en su excepción cuando se genera la excepción simulada. Por lo tanto, esto debería solucionarse eliminando "esperando":
allow_any_instance_of(Payment)
.to receive(:save)
.and_raise(CustomError)
3
En realidad, no incluí toda la prueba;He actualizado la publicación anterior, para que puedas ver que la clase descrita está ahí
-Carl
27/03/2021 a las 19:17
Oh, genial, entonces ignora la última parte. He actualizado la respuesta, espero que ayude
- Pablo
27/03/2021 a las 19:38
De hecho, creo que estoy confundiendo aún más las cosas porque ApplicationService implementa una llamada a un método de clase. Actualizaré above
-Carl
27/03/2021 a las 19:52