183 votes

Tester les modules dans RSpec

Quelles sont les meilleures pratiques pour tester les modules dans RSpec ? J'ai quelques modules qui sont inclus dans quelques modèles et pour l'instant j'ai simplement des tests dupliqués pour chaque modèle (avec quelques différences). Existe-t-il un moyen d'assécher les tests ?

229voto

metakungfu Points 820

La méthode rad =>

let(:dummy_class) { Class.new { include ModuleToBeTested } }

Vous pouvez également étendre la classe de test avec votre module :

let(:dummy_class) { Class.new { extend ModuleToBeTested } }

L'utilisation de 'let' est préférable à l'utilisation d'une variable d'instance pour définir la classe fictive dans le before(:each).

Quand utiliser RSpec let() ?

1 votes

Joli. Cela m'a permis d'éviter toutes sortes de problèmes avec les tests de spanning ivars de classe. J'ai donné des noms aux classes en les assignant à des constantes.

0 votes

Par "plus cool", @gri0n veut dire : que let est préférable à l'attribution d'une variable d'instance comme classe fictive dans une before(:each) (ou mieux before(:all) ). IMO, la meilleure raison est que vous obtiendrez une NameError au lieu de nil si tu le doigtes. Jetez un coup d'oeil à ce SO sur quand utiliser let

0 votes

J'aime ça. Elle fonctionne pour les méthodes définies dans le module. Mais, l'un de mes modules a des méthodes qui agissent sur les attributs de la classe contenant. J'ai essayé de les ajouter dans ma classe proxy définie dynamiquement avec attr_accessor, mais elles ne fonctionnent pas dans rspec. Curieusement, elles fonctionnent dans la console.

110voto

Karmen Blake Points 1675

Ce que Mike a dit. Voici un exemple trivial :

le code du module...

module Say
  def hello
    "hello"
  end
end

fragment de spec...

class DummyClass
end

before(:each) do
  @dummy_class = DummyClass.new
  @dummy_class.extend(Say)
end

it "get hello string" do
  expect(@dummy_class.hello).to eq "hello"
end

4 votes

Une raison pour laquelle vous n'avez pas include Say à l'intérieur de la déclaration de la DummyClass au lieu d'appeler extend ?

2 votes

Grant-birchmeier, il est extend dans l'instance de la classe, c'est-à-dire après avoir new a été appelé. Si vous faisiez cela avant new est appelé, alors vous avez raison, vous devriez utiliser include

8 votes

J'ai modifié le code pour être plus concis. @dummy_class = Class.new { extend Say } est tout ce dont vous avez besoin pour tester un module. Je pense que les gens préféreront cela, car nous, les développeurs, n'aimons pas taper plus que nécessaire.

31voto

Frank C. Eckert Points 356

Pour les modules qui peuvent être testés de manière isolée ou en simulant la classe, j'aime bien quelque chose du genre :

module :

module MyModule
  def hallo
    "hallo"
  end
end

spéc :

describe MyModule do
  include MyModule

  it { hallo.should == "hallo" }
end

Il peut sembler incorrect de détourner des groupes d'exemples imbriqués, mais j'aime la brièveté. Des idées ?

1 votes

J'aime ça, c'est si simple.

2 votes

Ça pourrait foutre en l'air le rspec. Je pense que l'utilisation du let La méthode décrite par @metakungfu est meilleure.

0 votes

@Cort3z Vous devez absolument vous assurer que les noms des méthodes n'entrent pas en collision. J'utilise cette approche uniquement lorsque les choses sont vraiment simples.

24voto

Andrius Points 785

J'ai trouvé une meilleure solution dans la page d'accueil de rspec. Apparemment, elle prend en charge les groupes d'exemples partagés. À partir de https://www.relishapp.com/rspec/rspec-core/v/2-13/docs/example-groups/shared-examples !

Groupes d'exemples partagés

Vous pouvez créer des groupes d'exemples partagés et inclure ces groupes dans d'autres groupes.

Supposons que vous ayez un comportement qui s'applique à toutes les éditions de votre produit, qu'elles soient petites ou grandes.

D'abord, il faut prendre en compte le "partagé" comportement :

shared_examples_for "all editions" do   
  it "should behave like all editions" do   
  end 
end

puis lorsque vous avez besoin de définir le comportement pour les éditions Large et Small, faites référence au comportement partagé en utilisant la méthode it_should_behave_like().

describe "SmallEdition" do  
  it_should_behave_like "all editions"
  it "should also behave like a small edition" do   
  end 
end

0 votes

21voto

Mike Woodhouse Points 27748

De mémoire, pourriez-vous créer une classe factice dans votre script de test et y inclure le module ? Puis testez que la classe factice a le comportement que vous attendez.

EDIT : Si, comme indiqué dans les commentaires, le module s'attend à ce que certains comportements soient présents dans la classe dans laquelle il est mélangé, alors j'essaierais d'implémenter des copies de ces comportements. Juste assez pour que le module soit heureux de remplir ses fonctions.

Si je n'hérite pas déjà d'une classe de base ou si je ne peux pas injecter la nouvelle fonctionnalité dans l'arbre d'héritage, je pense que j'essaierais de minimiser les attentes qu'un module pourrait avoir. Je crains que ma conception ne commence à développer certaines zones d'inflexibilité désagréable.

0 votes

Que faire si mon module dépend d'une classe ayant certains attributs et comportements ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X