2013-07-29 3 views
5

Mit FakeItEasy, wie überprüfe ich, ob die Methode meines Objekts eine andere Methode für das gleiche Objekt aufruft?Verwenden Sie A.CallTo() von FakeItEasy auf einer anderen Methode in demselben Objekt

Der Test:

[TestMethod] 
public void EatBanana_CallsWillEat() 
{ 
    var banana = new Banana(); 
    var myMonkey = new Monkey(); 

    myMonkey.EatBanana(banana); 

    //this throws an ArgumentException, because myMonkey is a real instance, not a fake 
    A.CallTo(() => myMonkey.WillEat(banana) 
    .MustHaveHappened(); 
} 

Die Klasse:

public class MyMonkey { 
    private readonly IMonkeyRepo _monkeyRepo; 

    public MyMonkey(IMonkeyRepo monkeyRepo) { 
    _monkeyRepo = monkeyRepo; 
    } 

    public void EatBanana(Banana banana) { 
    //make sure the monkey will eat the banana 
    if (!this.WillEat(banana)) { 
     return; 
    } 

    //do things here 
    } 

    public bool WillEat(Banana banana) { 
    return !banana.IsRotten; 
    } 
} 

Ich bin offen für Vorschläge. Wenn ich alles falsch mache, lass es mich wissen.

+2

Dies ist nicht wirklich, was FIE ist, wie ich es verstehe. FIE stellt gefälschte Objekte zur Verfügung, so dass Ihr Produktionscode einfacher gestochen werden kann. Wie Sie darauf hinweisen, haben Sie keine Fälschung. Meiner Erfahrung nach ist diese Art von Tests in der Regel keine gute Idee. Ihre MyMonkey-Klasse sollte eine ziemlich eigenständige Einheit sein, und Sie sollten besser sein Gesamtverhalten testen, wenn Sie eine Banane essen sollten, anstatt sich zu fragen, ob sie ihre eigenen Methoden nennt. Würden Sie zum Beispiel anhand von Hinweisen auf das, was in "// Dinge hier" passiert, wissen, ob die Banane gegessen wurde? –

+0

@BlairConrad in meinem realen Szenario ist WillEat komplexer und hat seine eigenen Tests, und dies ist nur einer der Tests EatBanana hat. Wenn ich in diesem Test EatBanana das echte WillEat nennen lasse, werde ich nicht zwei Features in einem Test testen? Dann, wenn sich WillEat änderte, konnte es diesen Test brechen, was schlechte Nachrichten sind, oder? –

+4

Ich verstehe deinen Standpunkt. Es ist schwierig. Wenn 'WillEat' auf einem anderen Objekt lebte, würden wir alle das Vortäuschen dieses Objekts drängen und es in' MyMonkey' injizieren (klingt schmerzhaft). Alles was ich wirklich sagen kann ist, dass ich denke, die beste Standardposition wäre es, 'MyMonkey' von außen zu testen, basierend auf den beobachtbaren Ergebnissen eines Kunden. Aber Sie haben darüber nachgedacht, und haben eine Lösung gefunden, die Ihnen Schmerzen ersparen wird und die Anzahl der Tests sowie die Zahl, die für eine gegebene bricht, reduziert. Du kennst den Code am besten, also wenn es für dich funktioniert ... Ich wollte nur, dass du dir der Alternative bewusst bist. –

Antwort

2

Es ist möglich, dies zu tun. Wenn die WillEat Methode wäre virtuell - sonst wird FakeItEasy nicht in der Lage sein, es zu fälschen.

Mit dieser Änderung könnten Sie dies tun:

[TestMethod] 
public void EatBanana_CallsWillEat() 
{ 
    var fakeMonkey = A.Fake<MyMonkey>(); 

    fakeMonkey.EatBanana(new Banana()); 

    A.CallTo(()=>fakeMonkey.WillEat(A<Banana>._)).MustHaveHappened(); 
} 

Ich bin noch nicht davon überzeugt, dass es eine gute Idee (wie ich in den Kommentaren ranted) - Ich glaube, Sie besser dran, die sich auf andere sein würde beobachtbares Verhalten, aber ich kenne Ihr System nicht. Wenn Sie denken, dass dies der beste Weg ist, sollte der Beispielcode für Sie funktionieren.

3

Warum verspotten Sie das getestete Objekt? Was genau versuchen Sie zu testen? Die Überprüfung, dass der Aufruf an WillEat stattgefunden hat, ist von geringem Wert. Welche Informationen werden dem Verbraucher zur Verfügung gestellt? Schließlich ist es dem Verbraucher egal, wie die Methode implementiert wird. Consumer interessiert was sind die Ergebnisse.

Was passiert, wenn Affe isst Banane, die ist nicht verfault? Ihr Test sollte diese Frage beantworten:

[TestMethod] 
public void EatBanana_CAUSES_WHAT_WhenBananaIsNotRotten() 
{ 
    var repo = A.Fake<IMonkeyRepo>(); 
    var monkey = new Monkey(repo); 
    var freshBanana = new Banana { IsRotten = false }; 

    monkey.EatBanana(freshBanana); 

    // verifications here depend on what you expect from 
    // monkey eating fresh banana 
} 

Beachten Sie, dass alle Arten von Überprüfungen IMonkeyRepo machen kann, was richtig vorgetäuscht wird und hier injiziert.

+0

Guter Punkt. Wenn ich WillEat nicht verspotze, und ich erlaube EatBanana, das echte WillEat zu nennen, teste ich zwei Features in einem Test?In diesem Beispiel ist WillEat trivial, aber in meiner tatsächlichen Situation ist es komplexer und gibt ein abgeleitetes Objekt basierend auf seinen Argumenten zurück, so dass ich dachte, es zu verspotten und zu überprüfen, dass es aufgerufen wurde, wäre der richtige Weg. Ich habe derzeit separate Tests für WillEat und einige andere Tests für EatBanana, einschließlich der Überprüfung, dass das Repo aufgerufen wurde. Vielleicht werde ich zu granular? –

+3

@JoshNoe: oder vielleicht wirst du nicht granular genug. Wenn 'WillEat' so komplex ist, sollte es vielleicht in seiner eigenen Klasse leben? Vielleicht macht es mehr Sinn, diese Eigenschaft zu * Essen-Evaluator-Art-Ding * zu extrahieren und es Affe zu injizieren? Tests * sollten * einfach sein - wenn sie es nicht sind * normalerweise * ist ein guter Hinweis darauf, dass Design überarbeitet werden kann. Nebenbei bemerkt: Warum sollte "Monkey" von "IMonkeyRepository" abhängen? –

Verwandte Themen