ruby on rails - tests - Acelerando las pruebas de RSpec en una gran aplicación de Rails
rspec rails 5 (12)
Tengo una aplicación Rails con más de 2,000 ejemplos en mis pruebas RSpec. No hace falta decir que es una aplicación grande y que hay mucho por probar. Ejecutar estas pruebas en este punto es muy ineficiente y, dado que lleva tanto tiempo, casi nos desalientamos de escribirlas antes de lanzar una nueva compilación. Agregué --profile a mi spec.opts para encontrar los ejemplos de ejecución más larga y hay al menos 10 de ellos que tardan un promedio de 10 segundos en ejecutarse. ¿Es eso normal entre ustedes los expertos de RSpec? ¿Son 10 segundos demasiado largos para un ejemplo? Me doy cuenta de que con 2,000 ejemplos, tomará una cantidad de tiempo no trivial probar todo a fondo, pero en este punto 4 horas es un poco ridículo.
¿Qué tipo de veces estás viendo para tus ejemplos de ejecución más larga? ¿Qué puedo hacer para solucionar mis especificaciones existentes a fin de descubrir los cuellos de botella y ayudar a acelerar las cosas? Cada minuto realmente ayudaría en este punto.
10 segundos es un tiempo muy largo para ejecutar cualquier prueba. Mi intuición es que su objetivo de especificación está ejecutando pruebas de unidad y de integración al mismo tiempo. Esto es algo típico de los proyectos y, en algún momento, deberá superar esta deuda técnica si desea producir más, más rápido. Hay una serie de estrategias que pueden ayudarlo a hacer esto ... y recomendaré algunas que he usado en el pasado.
1. Unidad separada de las pruebas de integración
Lo primero que haría es separar la unidad de las pruebas de integración. Puedes hacer esto ya sea por:
- Moverlos (a carpetas separadas bajo el directorio de especificaciones) y modificar los objetivos de rake
- Etiquetarlos (rspec le permite etiquetar sus pruebas)
La filosofía es que quieres que tus compilaciones regulares sean rápidas; de lo contrario, la gente no estará contenta de ejecutarlas con frecuencia. Así que regrese a ese territorio. Realice sus pruebas habituales para ejecutarlas rápidamente y utilice un servidor de integración continua para ejecutar la compilación más completa.
Una prueba de integración es una prueba que involucra dependencias externas (p. Ej. Base de datos, Servicio web, Cola, y algunos podrían argumentar FileSystem). Una prueba de unidad simplemente prueba el elemento específico de código que desea verificar. Debería ejecutarse rápidamente (9000 en 45 segundos es posible), es decir, la mayor parte debería ejecutarse en la memoria.
2. Convertir pruebas de integración a pruebas unitarias
Si la mayor parte de las pruebas de su unidad es más pequeña que su suite de prueba de integración, tiene un problema. Lo que esto significa es que las inconsistencias comenzarán a aparecer más fácilmente. Por lo tanto, desde aquí, comience a crear más pruebas unitarias para reemplazar las pruebas de integración. Las cosas que puede hacer para ayudar en este proceso son:
- Use un marco burlón en lugar del recurso real. Rspec tiene un marco de burla incorporado.
- Ejecute rcov en su suite de pruebas unitarias. Úselo para medir qué tan completo es el conjunto de pruebas de su unidad.
Una vez que tenga una prueba de unidad apropiada para reemplazar una prueba de integración, elimine la prueba de integración. Las pruebas duplicadas solo empeoran el mantenimiento.
3. No uses los accesorios
Los accesorios son malvados. Use una fábrica en su lugar (maquinista o factory_girl). Estos sistemas pueden generar gráficos de datos más adaptables y, lo que es más importante, pueden construir objetos en memoria que pueda usar, en lugar de cargar cosas desde una fuente de datos externa.
4. Agregue controles para detener las pruebas unitarias que se convierten en pruebas de integración
Ahora que tiene pruebas más rápidas en su lugar, es hora de poner controles para DETENER que esto vuelva a ocurrir.
Hay bibliotecas que montan el registro activo del parche para arrojar un error al intentar acceder a la base de datos (UnitRecord).
También puede probar el emparejamiento y TDD que pueden ayudar a obligar a su equipo a escribir pruebas más rápidas porque:
- Alguien está revisando, para que nadie se vuelva perezoso
- La TDD adecuada requiere una respuesta rápida. Las pruebas lentas solo hacen que todo sea doloroso.
5. Use otras bibliotecas para superar el problema
Alguien mencionó el spork (acelera los tiempos de carga para el banco de pruebas bajo rails3), hydra / parallel_tests - para ejecutar pruebas unitarias en paralelo (a través de múltiples núcleos).
Esto probablemente debería usarse ÚLTIMO. Su verdadero problema está en los pasos 1, 2 y 3. Resuelva eso y estará en una mejor posición para implementar la infraestructura adicional.
10 segundos por ejemplo parece mucho tiempo. Nunca he visto una especificación que duró más de un segundo, y la mayoría toma mucho menos. ¿Estás probando conexiones de red? ¿La base de datos escribe? Sistema de archivos escribe?
Use simulacros y talones tanto como sea posible; son mucho más rápidos que escribir código que llegue a la base de datos. Desafortunadamente, la burla y el troceo también toman más tiempo para escribir (y son más difíciles de hacer correctamente). Debe equilibrar el tiempo dedicado a escribir pruebas con el tiempo dedicado a ejecutar las pruebas.
Apoyo el comentario de Andrew Grimm sobre la búsqueda de un sistema de IC que podría permitirle paralelizar su conjunto de pruebas. Para algo de ese tamaño, podría ser la única solución viable.
Aquí hay un video muy general sobre cómo mejorar las velocidades de prueba. Podría ayudar.
Eliminar el conjunto de pruebas existente. Será increíblemente efectivo.
La gema más rápida de lo que necesita puede ser de ayuda. Además, su única forma es (como lo hizo) perfilar y optimizar, o usar spork o algo que ejecute sus especificaciones en paralelo para usted. http://ruby-toolbox.com/categories/distributed_testing.html
Para obtener un excelente libro de cocina sobre cómo mejorar el rendimiento de su suite de pruebas, consulte la presentación de Grease Your Suite .
Documenta una aceleración de 45x en el tiempo de ejecución de la serie de pruebas mediante el uso de técnicas tales como:
- fast_context
- quickerclip
- hydra
- ajustes del sistema de archivos de miedo
- tcmalloc
- Afinación de GC Ruby Enterprise Edition
Puede seguir algunos consejos sencillos para investigar primero dónde pasa la mayor parte del tiempo, si aún no los ha probado. Mira el artículo a continuación:
https://blog.mavenhive.in/7-tips-to-speed-up-your-webdriver-tests-4f4d043ad581
Creo que la mayoría de estos son pasos genéricos que se aplicarían independientemente de la herramienta utilizada para las pruebas también.
Puedes probar http://github.com/ngauthier/hydra
Puedes usar Spork. Tiene soporte para 2.3.x,
https://github.com/sporkrb/spork
o ./script/spec_server que puede funcionar para 2.x
También puede editar la configuración de la base de datos (lo que básicamente acelera las consultas de la base de datos, etc.), lo que también aumentará el rendimiento de las pruebas.
Si está utilizando modelos de ActiveRecord, también debe considerar el costo del cifrado de BCrypt.
Puede leer más sobre esto en esta publicación de blog: http://blog.syncopelabs.co.uk/2012/12/speed-up-rspec-test.html
Varias personas han mencionado a Hydra anteriormente. Lo hemos usado con gran éxito en el pasado. Recientemente documenté el proceso de poner en funcionamiento la hidra: http://logicalfriday.com/2011/05/18/faster-rails-tests-with-hydra/
Estoy de acuerdo con el sentimiento de que este tipo de técnica no debe utilizarse como sustituto de pruebas escritas que están bien estructuradas y son rápidas por defecto.
Verifique esta presentación: http://grease-your-suite.heroku.com/#1