38 votes

Quel est le double méthode dans rspec pour?

Il est indiqué dans la documentation de rspec que je devrais utiliser la méthode double pour créer un double de test. Mais je peux voir que ça fonctionne parfaitement même si je n'utilise pas double. Y a-t-il quelque chose de mal à ne pas utiliser double? De plus, si je n'utilise pas double, comment MyClass obtient-il stub et les autres méthodes rspec? Sont-elles disponibles pour tous les objets lors de l'exécution dans rspec?

require 'spec_helper'

class MyClass

    def self.run
        new.execute
    end

    def execute
        'foo'
    end

end

describe MyClass do

    it 'should stub instance method' do
        obj = MyClass.new
        obj.stub(:execute).and_return('bar')
        obj.execute.should == 'bar'
    end

    it 'should stub class method' do
        MyClass.stub(:run).and_return('baz')
        MyClass.run.should == 'baz'
    end

end

43voto

Jim Stewart Points 6811

Modifier : Je viens de relire votre question et je me rends compte que je ne l'ai pas vraiment répondue. Je laisse ma réponse initiale car elle est liée, mais voici votre réponse spécifique :

La raison pour laquelle vous n'avez pas besoin d'un double est que vous remplacez les méthodes de classe, plutôt que les méthodes d'instance. double est seulement utile pour traiter les instances de la classe, pas la classe elle-même.

Ancienne réponse expliquant un peu plus les doubles :

Vous devriez toujours utiliser de vraies classes au lieu de doubles de test lorsque vous le pouvez. Cela exercera plus de votre code et rendra vos tests plus complets. Les doubles de test sont utilisés dans des situations où vous ne pouvez pas ou ne devriez pas utiliser un objet réel. Par exemple, si une classe ne peut pas être instanciée sans accéder à une ressource externe (comme un réseau ou une base de données), ou possède un grand nombre de dépendances, et que vous testez simplement quelque chose qui l'utilise, vous voudrez peut-être créer un double et stubber certaines méthodes sur le double.

Voici un exemple plus spécifique : disons que vous testez MyClass, mais pour instancier MyClass, vous devez passer un FooLogger :

mylogger = FooLogger.new
myclass = MyClass.new logger: mylogger

Si FooLogger.new ouvre un socket syslog et commence à y envoyer du spam immédiatement, à chaque fois que vous lancez vos tests, vous serez en train de logger. Si vous ne voulez pas spammer vos logs pendant ce test, vous pouvez plutôt créer un double pour FooLogger et stubber une méthode dessus :

mylogger = double(FooLogger)
mylogger.stub(:log)
myclass = MyClass.new logger: mylogger

Parce que la plupart des classes bien conçues peuvent être instanciées sans aucun effet secondaire, vous pouvez généralement simplement utiliser l'objet réel au lieu d'un double, et stubber les méthodes sur celui-ci. Il existe d'autres scénarios où les classes ont de nombreuses dépendances qui les rendent difficiles à instancier, et les doubles sont une façon de contourner le superflu et de tester la chose qui vous intéresse vraiment.

Dans mon expérience, le besoin d'utiliser un double est un signe d'alerte dans le code, mais nous devons souvent utiliser des classes que nous ne pouvons pas facilement changer (par exemple, à partir d'une gemme), donc c'est un outil dont vous pourriez avoir besoin de temps en temps.

0voto

Avec RSpec Mocks 3.0, le comportement des doubles a changé. Vous pouvez maintenant vérifier les doubles, ce qui signifie que "RSpec vérifiera que les méthodes qui sont stubbées sont effectivement présentes sur l'objet sous-jacent s'il est disponible", mais "aucune vérification n'aura lieu si l'objet ou la classe sous-jacente n'est pas défini".

La vérification des doubles vous demande d'être spécifique quant au type de double (instance, classe, objet, classe dynamique, partielle). Voici un exemple du RSpec Relish pour un double d'instance :

RSpec.describe User, '#suspend!' do
  it 'notifies the console' do
    notifier = instance_double("ConsoleNotifier")

    expect(notifier).to receive(:notify).with("suspendu comme")

    user = User.new(notifier)
    user.suspend!
  end
end

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