Prueba de Rails::Prueba unitaria de validación del modelo sorprendentemente lenta – ¿I18n?
-
02-01-2020 - |
Pregunta
Tengo una prueba sencilla en mi aplicación Rails que siempre lleva mucho más tiempo que otras pruebas aparentemente similares.
Se necesitan de 1 a 2 segundos de tiempo real para ejecutarse. test_invalid_without_name
como a continuación:
VALID_PARAMS = { name: 'Client record' }
def test_invalid_without_name
c = Client.new(VALID_PARAMS)
c.name = nil
refute c.valid?, 'should not be valid without a name'
end
La próxima prueba, test_valid_with_all_params
tarda menos de 1/100 de segundo:
def test_valid_with_all_params
c = Client.new(VALID_PARAMS)
assert c.valid?, 'should be valid with appropriate parameters'
end
El modelo de Cliente es totalmente sencillo en esta etapa:
class Client < ActiveRecord::Base
belongs_to :entity, polymorphic: true
validates :name, presence: true
end
¿Alguien puede detectar lo que está mal aquí o darme una idea de dónde debería buscar a continuación para intentar resolverlo?
Actualización 1
He usado ruby-prof para perfilar el código, y parece que gran parte del tiempo se pasa en el Psicoanalizar joya.Creo que esto se usa en ActiveRecord::..#serialize
, que estoy usando en otro modelo de la siguiente manera:
class Opportunity < ActiveRecord::Base
belongs_to :client
serialize :details, Hash
end
Sin embargo, eliminar la llamada a serialize
aquí no hay ninguna diferencia en las pruebas del Cliente (y no veo por qué lo haría, las dos clases están asociadas, pero no se crean instancias de Oportunidades en la prueba del Cliente).
Actualización 2
Resulta que se llama a Psych porque I18n lo está usando.Mi suposición en este punto es que la validación fallida hace que I18n vaya a los archivos locales para mostrar un mensaje de error.Buscaré apagar I18n para realizar pruebas...
Solución
Resulta que un enfoque adecuado para resolver este problema fue utilizar Ruby-prof de la siguiente manera.
Agregar a Gemfile (en el development
grupo):
gem 'ruby-prof'
Envuelva el código de prueba en llamadas al generador de perfiles:
def test_invalid_without_name
RubyProf.start
cr = Client.new(VALID_PARAMS)
cr.name = nil
refute cr.valid?, 'should not be valid without a name'
result = RubyProf.stop
printer = RubyProf::CallStackPrinter.new(result)
printer.print(File.open(File.join(Rails.root, 'profile_invalid_without_name.html'), 'w'))
end
Esto creará un documento HTML interactivo en la raíz de su aplicación Rails, que muestra el desglose de dónde se dedica el tiempo.
En este caso, era más del 80% en I18n buscando traducciones.Agregué la siguiente línea a config/environments/test.rb
para apagarlo en la prueba:
I18n.backend = I18n::Backend::KeyValue.new({})
Probablemente haré las siguientes mejoras adicionales en el futuro:
Sea más específico con respecto a dónde eliminé I18n, para que las pruebas de aceptación de pila completa puedan utilizar el sistema real.
Escriba un enfoque de creación de perfiles más conveniente.Parece que ruby-prof ofrece varios otros mecanismos para activarlo, este fue el más simple para el uso inicial.
Otros consejos
No es posible responder a la pregunta sin más información.
- sucede esto cuando ejecuta cada una de las pruebas individualmente?
- ¿Tiene algo en la configuración / remonte o su test_helper.rb?
- sucede si pasa un hash con nombre=> nil en lugar de configurarlo?
- ¿Redefinió el conjunto de nombre?
- ¿Tiene alguna llamada de devolución de llamada en su modelo?