Wie werden Scheinobjekte häufig missbraucht?

15

Ich habe kürzlich einen Artikel gelesen, in dem es heißt, dass Scheinobjekte oft missverstanden und missbraucht werden. Gibt es eindeutige spöttische Anti-Muster, auf die ich achten kann?

Armand
quelle
ist der Artikel, den du gelesen hast? martinfowler.com/articles/mocksArentStubs.html
keppla
nein ... kann mich nicht an die genaue Quelle erinnern, werde aber hier posten
Armand
Ich wurde zum Stackoverflow gebracht, weil ich die Mongodb-API verspottet habe. Ich wurde auf einen Blog-Beitrag verwiesen, der behauptete, es sei falsch, eine Klasse zu verspotten, die Sie selbst nicht geschrieben haben. Ich bin damit eigentlich nicht einverstanden, aber die Meinung ist da draußen.
Kevin

Antworten:

13

Ich hasse es, wenn einfache konkrete Klassen verspottet werden. Nehmen Sie zum Beispiel die folgende einfache Klasse, die von nichts anderem abhängig ist:

public class Person
{
    private readonly string _firstName;
    private readonly string _surname;

    public Person(string firstName, string surname)
    {
        if (String.IsNullOrEmpty(firstName))
        {
            throw new ArgumentException("Must have first name");
        }

        if (String.IsNullOrEmpty(surname))
        {
            throw new ArgumentException("Must have a surname");
        }

        _firstName = firstName;
        _surname = surname;
    }

    public string Name 
    {
        get
        {
            return _firstName + " " + _surname;
        }
    }
}

Bei allen Tests, an denen diese Klasse beteiligt war, wäre es mir lieber, wenn eine echte instanziiert und verwendet würde, als dass eine Schnittstelle wie 'IPerson' herausgezogen, eine verspottete verwendet und Erwartungen an die. Wenn Sie den Real verwenden, ist Ihr Test realistischer (Sie haben die Parameterprüfungen und die reale Implementierung der 'Name'-Eigenschaft eingerichtet). Für eine einfache Klasse wie diese machen Sie Ihre Tests nicht langsamer, weniger deterministisch oder verwirren die Logik (Sie müssen wahrscheinlich nicht wissen, dass der Name beim Testen einer anderen Klasse aufgerufen wurde) - das sind die üblichen Gründe für das Verspotten / Stubbing.

Als Erweiterung dazu habe ich auch Leute gesehen, die Tests geschrieben haben, bei denen das Mock mit einer Erwartung eingerichtet wurde, dann wird das Mock direkt im Test aufgerufen. Es überrascht nicht, dass der Test immer bestanden wird ... hmmmm ...

FinnNk
quelle
Zum Glück habe ich Frameworks verspottet, mit denen ich konkrete Klassen verspotten konnte. Daher ist es kein Problem, Schnittstellen an unbequemen Stellen zu entfernen.
Armand
5
Das ändert nichts an dem Problem - solche einfachen Dinge sollten im Allgemeinen nicht verspottet werden, auch wenn Sie etwas verwenden, das die technischen Einschränkungen für das, was verspottet werden kann, lockert (z. B. ein verspottetes Framework wie TypeMock oder eine dynamische Sprache).
FinnNk
Meine Faustregel war immer, mich über das Verhalten lustig zu machen, nicht über Daten.
Ardave
10

Es mag offensichtlich klingen, aber: Verwenden Sie keine Scheinobjekte im Produktionscode! Ich habe mehr als ein Beispiel gesehen, in dem der Produktionscode von den Eigenschaften bestimmter Scheinobjekte abhing ( MockHttpServletRequestz. B. vom Springframework).

perdian
quelle
14
Ich hoffe, Sie sind Ihrer heiligen Pflicht gefolgt und haben den Code an DailyWTF übermittelt.
Keppla
1
In meiner vorherigen Arbeit war es uns ausdrücklich untersagt, irgendetwas aus unserer Codebasis an DWTF zu senden.
quant_dev
9
@quant_dev: Die Tatsache, dass sie eine solche Richtlinie hatten, impliziert beängstigende Dinge über ihre Entwickler ...
John Fisher
1
Nicht wirklich. Es war ein Startup, das schnell eine Codebasis entwickeln musste, um ein Produkt zu verkaufen, und dann damit begann, es zu konsolidieren und umzugestalten, um die technischen Schulden zu tilgen, da das Produkt ausgereift und die weitere Entwicklung durch das (fehlende) ursprüngliche Design behindert wurde. Die Manager wussten, dass es sich bei der alten Codebasis um Scheiße handelte, und investierten Zeit und Ressourcen in das Refactoring, wollten jedoch keine nachteilige Publizität riskieren.
quant_dev
Nur Abkürzungen nehmen ist nicht wirklich genug , um Sie nur DailyWTF zu bekommen ...
poolie
9

Meiner Meinung nach ist es die übermäßige Methodenaufrufprüfung für Mocks. Ich bin der Meinung, dass dies eine Praxis ist, die von einigen Spott-Frameworks wie EasyMock erzwungen wird, bei denen das Standard-Spott-Verhalten immer dann fehlschlägt, wenn ein zusätzlicher Methodenaufruf erfolgt, der zuvor nicht genau angegeben wurde. Diese Art der strengen Überprüfung von Scheinmethoden kann zu spröden Designs führen, bei denen die kleinste Änderung des Codes dazu führen kann, dass eine ganze Reihe von Tests fehlschlägt, obwohl die Kernfunktionalität immer noch dieselbe ist.

Eine Lösung für dieses Problem ist die Verwendung von Stichleitungen anstelle von Schein. Ein Artikel, den ich zu diesem Thema besonders aufschlussreich fand, wurde in Mockitos Javadoc gefunden: http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html (siehe "2. Wie wäre es mit Stubbing?" ), verlinkt auf: http://monkeyisland.pl/2008/07/12/should-i-worry-about-the-unexpected/ .

Bisher habe ich gerne mit Mockito gearbeitet, weil es dieses strenge Spottverhalten nicht erzwingt, sondern stattdessen Stubs verwendet. Es erzwingt auch die Methodenüberprüfung für bestimmte Objekte anstelle des gesamten Scheinobjekts. Am Ende überprüfen Sie nur die Methoden, die in Ihrem Testszenario wirklich wichtig sind.

Es gibt hier und da ein paar Bücher, die ich empfehlen kann, dieses Thema anzusprechen und spöttisch und allgemein:

xEinheitsmuster

Die Kunst des Unit Testing: Mit Beispielen in .Net

Java-Tests der nächsten Generation: TestNG und fortgeschrittene Konzepte (in diesem Buch geht es hauptsächlich um TestNG, aber es gibt ein nettes Kapitel über das Verspotten)

Fabio Kenji
quelle
+1 für den Punkt übermäßige Methodenaufrufprüfungen. Es gibt jedoch immer die Kehrseite der Medaille, auf der ein unerwarteter Methodenaufruf einen Fehler in Ihrer Methode verursacht. Zum Glück hat Mockito die Answer.RETURNS_SMART_NULLSEinstellung für Spott, die bei der Diagnose hilft.
Bringer128
4

Ich habe in meiner Erfahrung nur wenige Anti-Muster beobachtet.

  • Domänenklassen werden verspottet / gestubbt, wenn eine Statusänderung auftreten kann und dies überprüft werden muss.
  • Integrationstests interagieren mit einer Mischung aus Mocks und konkreten Klassen, die den Zweck von Integrationstests zunichte machen.
  • Versehentliche Verwendung von Mocks im Produktionscode (Dies sollte niemals passieren)

Ansonsten war meine Erfahrung mit Mocks, insbesondere Mockito, ein Kinderspiel. Sie haben Tests sehr einfach zu schreiben und zu warten gemacht. Das Testen von Interaktionen zwischen GWT-Ansicht und Moderator ist mit Mocks viel einfacher als mit dem GWTTestCase.

Vinod R
quelle
2 & 3 sind definitiv probleme! Haben Sie ein einfaches Beispiel für (1)?
Armand
2

Ich finde es besonders schwierig, Tests zu entschlüsseln und zu ändern, bei denen Mocks über mehrere Ebenen einer Anwendung hinweg verwendet werden. Ich denke jedoch, dass dies in den letzten Jahren durch verbesserte Mock-Framework-APIs gemildert wurde (ich verwende JMock, wo es angebracht ist).

Vor 5 oder 6 Jahren waren APIs wie EasyMock mächtig, aber sehr umständlich. Oft war der verwendete Testcode um Größenordnungen komplizierter als der getestete Code. Damals habe ich versucht, Teams zu beeinflussen, in denen ich sehr sparsam war, und mich mit einfachen handgefertigten Mocks zu begnügen, bei denen es sich lediglich um alternative Implementierungen von Schnittstellen handelte, die speziell für das Testen gedacht waren.

In letzter Zeit sind meine überzeugenden Meinungen dazu weicher geworden, da die spöttischen APIs Tests durchgeführt haben, in denen sie besser lesbar sind. Im Wesentlichen möchte ich, dass mein Code (einschließlich Tests) von anderen Entwicklern geändert werden kann, ohne dass sie das Gefühl haben, einen Sumpf dunkler API-Aufrufe zu durchlaufen.

Rupjones
quelle