Acelerar las pruebas de RSpec en una gran aplicación de Rails

90

Tengo una aplicación Rails con más de 2000 ejemplos en mis pruebas RSpec. No hace falta decir que es una gran aplicación y hay mucho que probar. Ejecutar estas pruebas en este punto es muy ineficiente y debido a que lleva tanto tiempo, estamos casi al punto de desanimarnos 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 2000 ejemplos, se necesitará una cantidad de tiempo no trivial para probar todo a fondo, pero en este punto, 4 horas es un poco ridículo.

¿Qué tipo de momentos está viendo para sus ejemplos más largos? ¿Qué puedo hacer para solucionar problemas de mis especificaciones existentes a fin de descubrir cuellos de botella y ayudar a acelerar las cosas? Cada minuto ayudaría mucho en este punto.

randombits
fuente
1
¿Las pruebas lentas son pruebas de integración? ¿Están llegando a una base de datos? Si es así, ¿con qué frecuencia se recarga la base de datos y puede burlarse de la base de datos?
Kaleb Pederson
1
¿Puede ejecutar solo parte de las especificaciones que son relevantes para la parte en la que está trabajando, similar al autotest de SeattleRB? ¿Tiene un servidor de integración continua que puede ejecutar todas las pruebas?
Andrew Grimm
Recuerda también que todas las cosas son relativas. Escuché "grrr, nuestro conjunto de pruebas tarda una eternidad" durante 20 minutos ... y entre 16 y 20 horas. Todo está en el ojo del espectador. 10 segundos para una prueba determinada a menudo significa una prueba unitaria que se ha convertido en una prueba de integración como se menciona a continuación.
Michael Durrant
Una sugerencia para este tipo de problema: utilícelo perftools.rbjunto con su marco de prueba para comprender qué está consumiendo la mayor parte de su tiempo. Tome las 10 principales llamadas e intente eliminarlas o eliminarlas. Luego repita, hasta que esté feliz.
aledalgrande

Respuestas:

118

10 segundos es mucho tiempo para que se ejecute una sola prueba. Mi intuición es que su objetivo de especificaciones está ejecutando pruebas unitarias y de integración al mismo tiempo. Esto es algo típico en lo que caen los proyectos y, en algún momento, deberá superar esta deuda técnica si desea producir más y 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. Puede hacer esto por:

  1. Moverlos (a carpetas separadas en el directorio de especificaciones) y modificar los objetivos de rake
  2. Etiquetarlos (rspec le permite etiquetar sus pruebas)

La filosofía es que desea que sus compilaciones habituales sean rápidas; de lo contrario, la gente no estará muy feliz de ejecutarlas a menudo. Así que vuelve a ese territorio. Haga que sus pruebas habituales se ejecuten 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 (por ejemplo, base de datos, servicio web, cola y algunos argumentarían que FileSystem). Una prueba unitaria solo prueba el elemento de código específico que desea verificar. Debería ejecutarse rápido (es posible 9000 en 45 segundos), es decir, la mayor parte debería ejecutarse en la memoria.

2. Convertir pruebas de integración en pruebas unitarias

Si la mayor parte de sus pruebas unitarias es más pequeña que su conjunto de pruebas de integración, tiene un problema. Lo que esto significa es que las inconsistencias comenzarán a aparecer más fácilmente. Entonces, a partir de 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:

  1. Utilice un marco burlón en lugar del recurso real. Rspec tiene un marco burlón incorporado.
  2. Ejecute rcov en su suite de pruebas unitarias. Úselo para medir qué tan completo es su conjunto de pruebas unitarias.

Una vez que tenga las pruebas unitarias adecuadas para reemplazar una prueba de integración, elimine la prueba de integración. Las pruebas duplicadas solo empeoran el mantenimiento.

3. No use accesorios

Los accesorios son malvados. En su lugar, utilice una fábrica (maquinista o robot de fábrica). Estos sistemas pueden crear gráficos de datos más adaptables y, lo que es más importante, pueden crear objetos en memoria que puede utilizar, en lugar de cargar cosas desde una fuente de datos externa.

4. Agregar comprobaciones para evitar que las pruebas unitarias se conviertan en pruebas de integración

Ahora que ha implementado pruebas más rápidas, es hora de realizar comprobaciones para DETENER que esto vuelva a ocurrir.

Hay bibliotecas que parchean el registro activo para arrojar un error al intentar acceder a la base de datos (UnitRecord).

También puede probar el emparejamiento y TDD, lo que puede ayudar a obligar a su equipo a escribir pruebas más rápidas porque:

  1. Alguien está comprobando, para que nadie se vuelva perezoso
  2. Una TDD adecuada requiere una respuesta rápida. Las pruebas lentas solo hacen que todo sea doloroso.

5. Utilice otras bibliotecas para solucionar el problema

Alguien mencionó spork (acelera los tiempos de carga para el conjunto de pruebas bajo rieles3), hydra / parallel_tests: para ejecutar pruebas unitarias en paralelo (en varios núcleos).

Esto probablemente debería usarse por ÚLTIMO. Su problema real está en los pasos 1, 2, 3. Resuelva eso y estará en una mejor posición para desplegar infraestructura adicional.

BlueFish
fuente
Gran respuesta. Es muy cierto que ninguna herramienta avanzada puede ayudar a ejecutar malas pruebas rápidamente. Así que intente escribir solo los buenos.
Yura Omelchuk
5
No estoy de acuerdo con su tercer punto de que no debe usar accesorios. Si se usan correctamente, son más rápidos que las fábricas, ya que no tiene que crear objetos. Sus datos están ahí, no tiene que crearlos con cada caso de prueba.
wallerjake
3
Esto de que las fábricas son más rápidas es una broma, ¿verdad?
Mike Szyndel
Acelere las
16

Para obtener un excelente libro de cocina sobre cómo mejorar el rendimiento de su suite de pruebas, consulte Grease Your Suite .

Documenta una aceleración de 45 veces en el tiempo de ejecución de la suite de pruebas mediante el uso de técnicas como:

mariscal
fuente
Me gustan los enlaces, pero no la presentación. Las tarjetas de índice para el discurso de alguien son una indicación para que el orador complete la esencia de la presentación.
Brian Maltzan
Esta presentación ya no está disponible. fast_context acelera varios bloques debidos. quickerclip (ese enlace también está muerto) aparentemente acelera Paperclip. Hydra está en desuso para las pruebas paralelas y Gorgon. bootsnap tiene ajustes en el sistema de archivos y ahora se incluye con Rails. Las versiones recientes de Ruby han mejorado la asignación y el GC.
rep
5

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 (que esencialmente acelera las consultas de la base de datos, etc.), lo que también aumentará el rendimiento de las pruebas.

Rishav Rastogi
fuente
Spork es increíble. También funciona en Rails 3, con un poco de pirateo. Pero una cosa a tener en cuenta con Spork on Rails 3 es que no parece detectar cambios en los controladores, por lo que deberá reiniciarlo de vez en cuando. Pero de todos modos, Spork es realmente impresionante, la mejora de la velocidad de las pruebas es muy significativa.
AboutRuby
4
Spork es solo para acelerar el inicio, no para realizar pruebas. Entonces, con muchas especificaciones, la ventaja es insignificante.
Reactormonk
Contrariamente a los comentarios anteriores, spork se puede utilizar para acelerar las pruebas y el inicio según railscast railscasts.com/episodios/285-spork . Mejoré enormemente mi conjunto de pruebas de rspec en una aplicación muy grande. (¡Reducido de 192 segundos a 10 segundos!)
jamesc
3

10 segundos por ejemplo parece mucho tiempo. Nunca he visto una especificación que demore más de un segundo, y la mayoría toma mucho menos. ¿Está probando las conexiones de red? ¿Escrituras de base de datos? ¿El sistema de archivos escribe?

Use simulacros y talones tanto como sea posible, son mucho códigos más rápidos que escribir código que llega a la base de datos. Desafortunadamente, las burlas y los tapones 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 pruebas.

Me segunda Andrew Grimm comentario 's de buscar en un sistema de CI que podría permitir que para paralelizar su serie de pruebas. Para algo de ese tamaño, podría ser la única solución viable.

zetético
fuente
sí, si son 10 segundos, lo perfilaría y vería dónde está el cuello de botella
rogerdpack
1
Tengo un proyecto enorme y ejecutar una única prueba de rspec tarda entre 15 y 20 segundos.
Exire el
2

Varias personas han mencionado a Hydra anteriormente. Lo hemos utilizado con gran éxito en el pasado. Recientemente documenté el proceso de puesta en marcha de Hydra: http://logicalfriday.com/2011/05/18/faster-rails-tests-with-hydra/

Estoy de acuerdo con la opinión de que este tipo de técnica no debería utilizarse como sustituto de las pruebas de redacción que están bien estructuradas y son rápidas por defecto.

Rodreegez
fuente
-4

Elimine el conjunto de pruebas existente. Será increíblemente efectivo.

thedanotto
fuente