2009-07-22 7 views
32

Existe-t-il un moyen de copier Kernel.sleep dans un scénario rspec?RSpec: stubbing Kernel :: sommeil?

+0

Vous cherchez quelque chose au-delà de Kernel :: stubs (: sleep) –

+0

J'imagine qu'il voudrait que ça marche et ne dorme pas, peut-être ralentir son test ... – Rich

Répondre

43

Si vous appelez le sommeil dans le contexte d'un objet, vous devez stub sur l'objet, comme suit:

class Foo 
    def self.some_method 
    sleep 5 
    end 
end 

it "should call sleep" do 
    Foo.stub!(:sleep) 
    Foo.should_receive(:sleep).with(5) 
    Foo.some_method 
end 

la clé est, à dormir sur stub quel que soit le "soi" dans le contexte où le sommeil est appelé.

+1

Travaillé génial pour moi, bravo! – opsb

+0

La réduction de l'objet à tester n'est pas une bonne idée. Pour des exemples, voir: http://robots.thoughtbot.com/don-t-stub-the-system-under-test – georgebrock

+1

@georgebrock pour une raison non pertinente, n'est ce pas? Je crois que [this] (http://stackoverflow.com/a/27749263/52499) est le moyen qui exprime le mieux l'intention. Et doit utiliser une syntaxe plus récente. 'allow_any_instance_of (Object) .pour recevoir (: sleep)' –

2

si vous utilisez Mocha, alors quelque chose comme cela fonctionnera:

def setup 
    Kernel.stubs(:sleep) 
end 

def test_my_sleepy_method 
    my_object.take_cat_nap! 
    Kernel.assert_received(:sleep).with(1800) #should take a half-hour paower-nap 
end 

Ou si vous utilisez rr:

def setup 
    stub(Kernel).sleep 
end 

def test_my_sleepy_method 
    my_object.take_cat_nap! 
    assert_received(Kernel) { |k| k.sleep(1800) } 
end 

Vous probablement ne doit pas être un test plus problèmes de thread complexes avec des tests unitaires. Cependant, sur les tests d'intégration, utilisez le vrai Kernel.sleep, qui vous aidera à résoudre les problèmes de threads complexes.

4

En rspec pur:

before do 
    Kernel.stub!(:sleep) 
end 

it "should sleep" do 
    Kernel.should_receive(:sleep).with(100) 
    Object.method_to_test #We need to call our method to see that it is called 
end 
+8

Pour clarifier, parce que ça n'a pas fonctionné pour moi tout de suite, tu dois appeler Kernel .sleep, afin de se moquer de cette façon. Le simple appel du sommeil échoue directement –

+0

Oui, la méthode que vous appelez aura ce sommeil. – nitecoder

0

je devais bouchonner requiers et après de longues recherches, je trouve que la seule façon qui a fonctionné pour moi ce

def method_using_sleep 
    sleep 
    sleep 0.01 
end 

it "should use sleep" do 
    @expectations = mock('expectations') 
    @expectations.should_receive(:sleep).ordered.with() 
    @expectations.should_receive(:sleep).ordered.with(0.01) 

    def sleep(*args) 
    @expectations.sleep(*args) 
    end 

    method_using_sleep 
end 
0

Je n'ai pas réussi à obtenir les autres solutions ici. Peut-être que quelque chose a changé dans la façon dont le sommeil est géré dans les nouvelles versions de Ruby, ou quelque chose d'autre. Ce que j'ai fini par faire était de corriger la classe Object car il semble que c'est ce qui reçoit les appels de sommeil. Donc, j'ai simplement ajouté ceci:

class Object 
    def sleep(*args) 
    end 
end 

Ainsi, la méthode de sommeil ne plus rien au lieu de quelque chose. Il pourrait y avoir un moyen de se moquer de cela mieux, mais je ne pouvais pas trouver une bonne solution sans se moquer du sleep metohd de chaque objet qui l'utilisait potentiellement.

+0

S'il vous plaît voir ma solution ci-dessous. rspec-mock est ici, donc vous n'avez pas besoin de patch – Benj

11

Lorsque l'appel à sleep est pas dans un objet (tout en testant une tâche de coupe par exemple), vous pouvez ajouter ce qui suit dans un avant bloc (rspec 3 syntaxe)

allow_any_instance_of(Object).to receive(:sleep)