Prueba de unidad RSPEC con múltiples afirmaciones
-
21-12-2019 - |
Pregunta
En primer lugar, sé que es una mala práctica tener múltiples afirmaciones en la prueba de la unidad.
Pero a veces necesitas probar alguna transacción atómica.Como ejemplo simplificado, tomemos alguna aplicación bancaria que tenga la clase de cuenta:
class Account
attr_accessor :balance
def transfer(to_account, amount)
self.balance -= amount
to_account.balance += amount
Audit.create(message: "Transferred #{amount} from #{self.number} to #{to_account.number}."
end
end
En esta situación, quiero verificar 3 cosas juntas:
- Balance de la cuenta de origen disminuyó por
amount
El saldo de la cuenta de destino - incrementado por
amount
- se inserta el registro de auditoría
¿Cuál es la mejor manera de probar el método @account.transfer
?
Solución
En esta situación, quiero verificar 3 cosas juntas:
Argumentaría que lo que realmente quiere es describir el comportamiento de estas cosas bajo ciertas condiciones, y así garantizar que el comportamiento cumpla con sus especificaciones. Eso podría significar que las cosas sucedan juntas; o podría significar que algunas cosas solo ocurren en un conjunto de condiciones y no a otras personas, o que una excepción hace que todo se vuelva a rodar hasta su estado original.
No hay magia para tener todas sus afirmaciones en una prueba, excepto para hacer las cosas más rápido. A menos que se enfrente a una penalización severa de desempeño (a menudo sucede en las pruebas de pila completa), es mucho mejor usar una afirmación por prueba.
rspec lo hace directo para extraer la fase de configuración de prueba para que se repita para cada ejemplo:
class Account
attr_accessor :balance
def transfer(to_account, amount)
self.debit!(amount)
to_account.credit!(amount)
Audit.create!(message: "Transferred #{amount} from #{self.number} to #{to_account.number}."
rescue SomethingBadError
# undo all of our hard work
end
end
describe Account do
context "when a transfer is made to another account" do
let(:other_account} { other_account }
context "and the subject account has sufficient funds" do
subject { account_with_beaucoup_bucks }
it "debits the subject account"
it "credits the other account"
it "creates an Audit entry"
end
context "and the subject account is overdrawn" do
subject { overdrawn_account }
it "does not debit the subject account"
it "does not credit the other account"
it "creates an Audit entry" # to show the attempted transfer failed
end
end
end
Si las tres pruebas en el "camino feliz" pasaban, entonces todos "sucedieron juntos", ya que el estado del sistema inicial era el mismo en cada caso.
Pero también necesita asegurarse de que las cosas no suceden cuando algo sale mal y que el sistema vuelve a su estado original. Tener múltiples afirmaciones hace que sea fácil ver que esto funciona como se esperaba, y cuando las pruebas fallan, exactamente cómo Falló.
Otros consejos
Las múltiples afirmaciones por prueba no siempre son una mala práctica. Si los múltiples afirman verifican el mismo comportamiento, no hay problema con él. El problema existe al intentar verificar más de un comportamiento en la misma prueba. Por supuesto, hay algunos riesgos con múltiples afirmaciones por prueba. Uno de ellos es que accidentalmente puede dejar valores de un conjunto de prueba anterior que invalida una prueba anterior de una manera rara. Además, cuando una afirmación es falsa, no se ejecutará todo lo demás, lo que puede causar dificultades para entender lo que está pasando. Pero sea razonable, puede tener múltiples afirmaciones que afirman el mismo comportamiento, preferiblemente las cortas y sin configuración adicional.
En el caso simple que trajo, usaría múltiples afirmaciones, porque es tan simple. Pero, por supuesto, puede ser mucho más complicado, como el equilibrio negativo, los diferentes tipos de cuentas y cosas. Entonces sería mejor usar diferentes pruebas con una (preferiblemente) afirmación. Lo organizaría así:
- 1 para probar el comportamiento de la cuenta corriente (caso más simple);
- 1 a cada camino diferente El método puede tener (excepciones, negativas equilibrio, etc.);
-
1 para probar la auditoría en cada una de estas posibilidades;
-
1 para probar el comportamiento de la actualidad actual (caso más simple);
- 1 a cada camino diferente El método puede tener. (excepciones, negativas equilibrio, etc.);
- 1 para probar la auditoría en cada una de estas posibilidades;
Dado que la prueba de auditoría es bastante simple y no requiere una configuración adicional, también puede probarlo junto con la cuenta y la configuración.