web-dev-qa-db-fra.com

Accélérer les tests RSpec dans une grande application Rails

J'ai une application Rails avec plus de 2 000 exemples dans mes tests RSpec. Inutile de dire que c'est une grande application et qu'il y a beaucoup à tester. L'exécution de ces tests à ce stade est très inefficace et parce que cela prend tellement de temps, nous sommes presque sur le point d'être découragés de les écrire avant de pousser une nouvelle construction. J'ai ajouté --profile à mes spécifications.opts pour trouver les exemples les plus longs et il y en a au moins 10 qui prennent 10 secondes en moyenne. Est-ce normal parmi vous les experts RSpec? Est-ce que 10 secondes sont trop longues pour un exemple? Je me rends compte qu'avec 2 000 exemples, il faudra un temps non négligeable pour tout tester à fond - mais à ce point 4 heures est un peu ridicule.

Quel genre de fois voyez-vous pour vos exemples les plus anciens? Que puis-je faire pour dépanner mes spécifications existantes afin de trouver des goulots d'étranglement et aider à accélérer les choses. Chaque minute serait vraiment utile à ce stade.

90
randombits

10 secondes sont très longues pour exécuter un seul test. Mon intuition est que votre cible de spécification exécute des tests unitaires et d'intégration en même temps. C'est une chose typique dans laquelle les projets entrent et à un moment donné, vous devrez surmonter cette dette technique si vous voulez produire plus, plus rapidement. Il existe un certain nombre de stratégies qui peuvent vous aider à le faire ... et je vais en recommander quelques-unes que j'ai utilisées dans le passé.

1. Séparez l'unité des tests d'intégration

La première chose que je ferais serait de séparer l'unité des tests d'intégration. Vous pouvez le faire soit par:

  1. Les déplacer (dans des dossiers séparés sous le répertoire spec) - et modifier les cibles de râteau
  2. Les étiqueter (rspec vous permet de baliser vos tests)

La philosophie est que vous voulez que vos versions régulières soient rapides - sinon les gens ne seront pas trop heureux de les exécuter souvent. Revenez donc sur ce territoire. Exécutez rapidement vos tests réguliers et utilisez un serveur d'intégration continue pour exécuter la version la plus complète.

Un test d'intégration est un test qui implique des dépendances externes (par exemple, Database, WebService, Queue, et certains diront FileSystem). Un test unitaire teste simplement l'élément de code spécifique que vous souhaitez vérifier. Il devrait fonctionner rapidement (9000 en 45 secondes est possible), c'est-à-dire que la plupart devraient fonctionner en mémoire.

2. Convertir les tests d'intégration en tests unitaires

Si la majeure partie de vos tests unitaires est plus petite que votre suite de tests d'intégration, vous avez un problème. Cela signifie que les incohérences commenceront à apparaître plus facilement. À partir d'ici, commencez à créer plus de tests unitaires pour remplacer les tests d'intégration. Les choses que vous pouvez faire pour aider dans ce processus sont les suivantes:

  1. Utilisez un cadre moqueur au lieu de la vraie ressource. Rspec a un cadre de simulation intégré.
  2. Exécutez rcov sur votre suite de tests unitaires. Utilisez-le pour évaluer la profondeur de votre suite de tests unitaires.

Une fois que vous avez un ou des tests unitaires appropriés pour remplacer un test d'intégration - supprimez le test d'intégration. Des tests en double ne font qu'empirer la maintenance.

. N'utilisez pas de luminaires

Les luminaires sont mauvais. Utilisez plutôt une usine (machiniste ou fille_usine). Ces systèmes peuvent créer des graphiques de données plus adaptables et, plus important encore, ils peuvent créer des objets en mémoire que vous pouvez utiliser, plutôt que de charger des éléments à partir d'une source de données externe.

4. Ajoutez des contrôles pour que les tests unitaires ne deviennent pas des tests d'intégration

Maintenant que vous avez mis en place des tests plus rapides, il est temps de vérifier si cela ne se reproduit plus.

Il y a des bibliothèques qui enregistrent activement les patchs de singe pour générer une erreur lors de l'accès à la base de données (UnitRecord).

Vous pouvez également essayer l'appariement et le TDD, ce qui peut forcer votre équipe à écrire des tests plus rapides car:

  1. Quelqu'un vérifie - pour que personne ne devienne paresseux
  2. Un TDD correct nécessite une rétroaction rapide. Les tests lents rendent la chose douloureuse.

5. Utilisez d'autres bibliothèques pour surmonter le problème

Quelqu'un a mentionné spork (accélère les temps de chargement de la suite de tests sous Rails3), hydra/parallel_tests - pour exécuter des tests unitaires en parallèle (sur plusieurs cœurs).

Cela devrait probablement être utilisé EN DERNIER. Votre vrai problème est tout au long des étapes 1, 2, 3. Résolvez-le et vous serez mieux placé pour déployer des infrastructures supplémentaires.

119
BlueFish

Pour un excellent livre de recettes sur l'amélioration des performances de votre suite de tests, consultez la présentation Grease Your Suite .

Il documente une accélération de 45x lors de l'exécution de la suite de tests en utilisant des techniques telles que:

16
marshally

Vous pouvez utiliser Spork. Il prend en charge 2.3.x,

https://github.com/sporkrb/spork

ou ./script/spec_server qui peut fonctionner pour 2.x

Vous pouvez également modifier la configuration de la base de données (ce qui accélère essentiellement les requêtes de base de données, etc.), ce qui augmentera également les performances des tests.

5
Rishav Rastogi

10 secondes par exemple semblent être très longues. Je n'ai jamais vu une spécification qui a pris plus d'une seconde, et la plupart en prennent beaucoup moins. Testez-vous les connexions réseau? La base de données écrit? Le système de fichiers écrit?

Utilisez autant que possible des simulacres et des talons - ils sont beaucoup plus rapides que l'écriture de code qui frappe la base de données. Malheureusement, la moquerie et le stubbing prennent également plus de temps à écrire (et sont plus difficiles à faire correctement). Vous devez équilibrer le temps passé à écrire des tests et le temps passé à exécuter les tests.

Je second Andrew Grimm commente la recherche d'un système CI qui pourrait vous permettre de paralléliser votre suite de tests. Pour quelque chose de cette taille, ce pourrait être la seule solution viable.

3
zetetic

Si vous utilisez des modèles ActiveRecord, vous devez également prendre en compte le coût du chiffrement BCrypt.

Vous pouvez en savoir plus à ce sujet sur cet article de blog: http://blog.syncopelabs.co.uk/2012/12/speed-up-rspec-test.html

2
Erdem Gezer

Plusieurs personnes ont mentionné Hydra ci-dessus. Nous l'avons utilisé avec beaucoup de succès dans le passé. J'ai récemment documenté le processus de mise en service d'hydre: http://logicalfriday.com/2011/05/18/faster-Rails-tests-with-hydra/

Je suis d'accord avec le sentiment que ce type de technique ne doit pas être utilisé comme substitut à des tests d'écriture bien structurés et rapides par défaut.

2
Rodreegez

Découvrez cette présentation: http://grease-your-suite.heroku.com/#1

1
user456733

Il y a une vidéo très générale ici sur l'amélioration de vos vitesses de test. Pourrait aider.

0
Neil

Vous pouvez suivre quelques conseils simples pour d'abord déterminer où la plupart du temps est passé si vous ne les avez pas déjà essayés. Regardez l'article ci-dessous:

https://blog.mavenhive.in/7-tips-to-speed-up-your-webdriver-tests-4f4d043ad581

Je suppose que la plupart d'entre elles sont des étapes génériques qui s'appliqueraient indépendamment de l'outil utilisé pour les tests également.

0
jake
0
Reactormonk

plus rapide_require gem pourrait vous aider. En plus de cela, votre seul moyen est (comme vous l'avez fait) de profiler et d'optimiser, ou d'utiliser du spork ou quelque chose qui exécute vos spécifications en parallèle pour vous. http://Ruby-toolbox.com/categories/distributed_testing.html

0
rogerdpack