Test de taille de bloc Rubocop 25 lignes et RSpec

Un test unitaire RSpec typique utilise largement les blocs Ruby nesteds afin de structurer le code et d’utiliser la “magie” DSL pour que les spécifications soient lues comme les instructions BDD:

describe Foo do context "with a bar" do before :each do subject { Foo.new().add_bar } end it "looks like a baz" do expect # etc 

Dans une spécification idéale, chaque exemple peut être relativement court et précis. Cependant, il semble habituel que les blocs externes atteignent 100 lignes de plus, car la structure RSpec fonctionne de cette manière et ne prend pas beaucoup d’exemples, chacun pouvant avoir quelques lignes de configuration spécifique, pour describe blocs qui sont la même taille ou plus grande que le code du sujet décrit.

Une récente mise à jour de Rubocop a entraîné une nouvelle règle, à savoir que les blocs ne doivent pas dépasser 25 lignes. Je ne suis pas sûr de la raison, car il ne figure pas dans le guide de style Ruby . Je peux voir pourquoi cela pourrait être une bonne chose, et ajouté à l’ensemble de règles par défaut. Cependant, après la mise à niveau, notre test Rubocop échoue plusieurs fois avec des messages tels que tests/component_spec.rb:151:3: C: Block has too many lines. [68/25] tests/component_spec.rb:151:3: C: Block has too many lines. [68/25]

Avec les outils de mesure de code tels que Rubocop, j’aime avoir une politique de “Utiliser les parameters par défaut, un lien vers le guide de style, le travail effectué”. (principalement parce que débattre les tabs vs les espaces et autres minuties est une perte de temps et que l’IME n’est jamais résolu) Ici, ce n’est clairement pas possible, deux de nos principaux outils de qualité des données ne sont pas d’accord , Je ne vois rien de insortingnsèquement faux avec la façon dont nous avons écrit les spécifications.

En réponse, nous avons simplement défini la règle de taille de bloc Rubocop sur un seuil élevé. Mais cela me fait penser – qu’est-ce qui me manque? RSpec utilise-t-il une approche désormais discréditée pour la mise en page du code et quelles sont les options raisonnables pour réduire la taille des blocs dans nos tests RSpec? Je peux voir des moyens de restructurer le code pour éviter les gros blocs, mais ils sont sans exception des hacks laids conçus uniquement pour répondre à la règle de Rubocop. Par exemple, divisez tous les blocs en fonctions d’aide:

 def looks_like_a_baz it "looks like a baz" do expect # etc end end def bar_context context "with a bar" do before :each do subject { Foo.new().add_bar } end looks_like_a_baz end end describe Foo do bar_context # etc 

. . . Je veux dire, c’est faisable, mais transformer les paquets d’exemples de spécification en fonctions d’assistance semble être le contraire de l’approche lisible encouragée par la conception de RSpec.

Est-ce que je peux faire autre chose que trouver des moyens de l’ignorer?


La question existante la plus proche que je pouvais trouver sur ce sujet ici était RSpec & Rubocop / Ruby Style Guide .

Une récente mise à jour de Rubocop a entraîné une nouvelle règle, à savoir que les blocs ne doivent pas dépasser 25 lignes. Je ne suis pas sûr de la raison, car il ne figure pas dans le guide de style Ruby.

Auparavant, tous les flics étaient basés sur le Ruby Style Guide, et RuboCop était un moyen d’adhérer aux pratiques définies par la communauté.

La direction a changé depuis, et la scope de RuboCop s’est élargie pour aider les développeurs à assurer la cohérence de leurs bases de code en général. Cela a conduit à deux choses:

  1. Les flics (même ceux basés sur le Ruby Style Guide) sont maintenant configurables pour la plupart.
  2. Il y a des flics pour les choses qui ne sont pas mentionnées dans le Guide de style Ruby, mais qui sont toujours utiles pour renforcer la cohérence dans un projet.

Ce flic entre dans la deuxième catégorie.

RSpec utilise-t-il une approche désormais discréditée pour la mise en page du code et quelles sont les options raisonnables pour réduire la taille des blocs dans nos tests RSpec?

La réponse courte est non. Les DSL sont toujours cool. 🙂

Ce flic vise gros bloc dans le sens impératif de la programmation. En règle générale, il ne s’applique pas aux DSL, qui sont souvent déclaratives. Par exemple, avoir un long fichier routes.rb dans Rails est parfaitement bénin. C’est simplement le résultat naturel d’une application volumineuse, plutôt qu’une violation de style. (Et avoir beaucoup de tests est purement génial.)

Maintenant, RuboCop est assez intelligent, mais il ne sait pas ce qu’est un DSL et pas, donc nous ne pouvons pas les ignorer automatiquement. On pourrait soutenir que nous pourrions exclure les méthodes d’entrée DSL des frameworks populaires, comme les routes Rails et les spécifications RSpec. Les raisons pour ne pas le faire sont principalement:

  1. Faux négatifs. Toute classe peut implémenter une méthode, en prenant un bloc du même nom.
  2. RuboCop est un outil d’parsing Ruby, et ne devrait pas vraiment connaître les bibliothèques externes. (L’exclusion du répertoire /spec est une courtoisie jusqu’à ce que nous ayons un système d’extension approprié, et cela peut être géré par le rubocop-rspec .)

Je veux dire, c’est faisable, mais transformer les paquets d’exemples de spécification en fonctions d’assistance semble être le contraire de l’approche lisible encouragée par la conception de RSpec.

La ligne de fond est la suivante: RuboCop est là pour nous aider à écrire un meilleur code. Si la conception de notre application est par ailleurs saine et que nous nous rendons moins lisibles simplement pour plaire à RuboCop, nous devrions alors filtrer, configurer ou désactiver le copieur. 🙂

En réponse, nous avons simplement défini la règle de taille de bloc Rubocop sur un seuil élevé. Mais cela me fait penser – qu’est-ce qui me manque?

C’est un outil assez brutal et, comme vous le dites, vous aurez probablement des faux négatifs à cause de cela. Il existe deux types de faux positifs pour ce flic:

  1. Fichiers contenant des DSL purement déclaratives, par exemple des routes Rails, des spécifications RSpec.
  2. Les fichiers qui ont un DSL déclaratif mélangés dans un code essentiellement impératif, par exemple une déclaration de machine à états aasm dans un modèle Rails.

Dans le premier cas, la meilleure solution consiste à exclure le fichier ou le répertoire et, dans le second, à utiliser une désactivation en ligne.

Dans votre cas, vous devriez mettre à jour votre .rubocop.yml avec:

 Mesortingcs/BlockLength: Exclude: - 'Rakefile' - '**/*.rake' - 'test/**/*.rb' 

(Notez que vous devez réitérer les exclusions de base de la configuration par défaut, car la liste sera remplacée.)


Disclaimer: Je suis un consortingbuteur fréquent de RuboCop, mais pas un responsable. Je base ce qui précède sur ma meilleure compréhension de travailler avec la base de code et de suivre beaucoup de problèmes.

Si un bloc spécifique est généralement trop long, je le spécifie plutôt que les fichiers

 Mesortingcs/BlockLength: ExcludedMethods: ['describe', 'context']