# Testen mit Mockito ohne Delegation?



## dodik4711 (21. Okt 2011)

Hallo Leute,

ich kämpfe gerade etwas mit Mockito und bräuchte eure Hilfe.
Um das Beispiel etwas verständlicher zu machen erkläre ich den aktuellen Stand in vereinfachter Form.

Ich habe eine Benchmark Klasse deren Aufgabe es ist, einen beliebigen Task zu erledigen.
Die Benchmark Klasse hat einen Konstruktor (der einen Dateipfad erwartet) und eine executeBenchmark() Methode.
Der Konstruktor verarbeitet die empfangene Datei "irgendwie" um nähere Informationen zu dem Task zu gewinnen.
Die executeBenchmark()-Methode instantiiert ein *BenchmarkTask* Objekt mit den, aus der Datei gewonnenen, informationen und führt den Task danach aus.

Hier ein stark vereinfachter Code.

```
public class Benchmark {
    private String taskDescription ;

    public Benchmark(String pathToBenchmarkFile) {
        taskDescription = processBenchmarkFile(pathToBenchmarkFile) ;
    }

    public void executeBenchmark() {
        BenchmarkTask task  = new BenchmarkTask(taskDescription) ;
        task.executeTask();
    }
}
```

Jetzt würde ich gerne einen Test schreiben, der die executeBenchmark()-Methode ausführt und sicherstellt, dass die *executeTask()*-Methode 1 mal aufgerufen wurde.

Nun stoße ich aber auf mindestens 2 Probleme. 
Normalerweise mockt man ja eine Klasse und delegiert das Objekt weiter um es sozusagen "einzuschleusen".

Also ungefähr so:

```
public void shouldCallExecuteTask() {
        BenchmarkTask mockedTask = Mockito.mock(BenchmarkTask.class) ;

        Benchmark benchmark = new Benchmark("someFile.txt") ;
        // hier wird das Objekt delegiert
        benchmark.executeBenchmark(mockedTask);

        Mockito.verify(mockedTask, Mockito.times(1)).executeTask();
}
```

Die Methode executeBenchmark() erwartet jedoch keine Delegation. Problem Nr. 1!
"Nicht schlimm" dachte ich mir und habe einfach eine eingebaut, womit ich auf das zweite Problem aufmerksam wurde.


```
// mit eingebauter Delegation
public void executeBenchmark(BenchmarkTask task) {
        task  = new BenchmarkTask(taskDescription) ;
        task.executeTask();
}
```

Problem Nr. 2: Auch wenn das gemockte Objekt hierhin delegiert wurde, instantiert die Methode ja trotzdem ein "echtes" BenchmarkTask Objekt. 

Kann man in diesem Fall denn überhaupt mocken? Und wenn ja, wie?

Hoffe ich habe es verständlich genug gemacht und bedanke mich im Voraus.


----------



## Gelöschtes Mitglied 6946 (21. Okt 2011)

Variante 2 bringt dir gar nichts, da du die übergebene Referenz sofort überschreibst, das dahinterliegende Objekt wird also gar nicht weiter angefasst von deinem Benchmark. Du könntest das Problem damit umgehen, dass du eine Factory für BenchmarkTasks anlegst, die du wiederum an den Benchmark übergibst und diese könntest du in ein Mock packen und wiederum einen Mock von BenchmarkTask herauszugeben. Aber das ist im Grunde übertriebene Komplexität für das, was du machst.

Für mich stellt sich ein wenig die Frage, wo denn ein Ergebnis herauskommt aus deinem Programm. Der Benchmark sollte ein Ergebnis liefern und dieses sollte zurückgegeben werden oder anderweitig zugreifbar sein. Dann könntest du schonmal testen, dass etwas korrektes rauskommt. Darüber hinaus wäre ein Konstruktor, der bereits eine fertige taskDescription bekommt, sehr schön, denn für einen Test erst zwangsläufig aus einer Datei lesen zu müssen, ist vielleicht auch nicht das Wahre (bzw. man könnte es getrennt voneinander testen). Wenn du schließlich eine definierte Eingabe hast und eine prüfbare Ausgabe bekommst, dann ist es auch nicht mehr schlimm, dass du den BenchmarkTask nicht mocken kannst, da das sowieso versteckt ist. Zwar testest du diese Klasse dann implizit mit (was einem Unit-Test etwas wiederspricht), aber ich sehe auf die Schnelle auch keine andere Möglichkeit.


----------



## dodik4711 (21. Okt 2011)

ex'ratt hat gesagt.:


> Zwar testest du diese Klasse dann implizit mit (was einem Unit-Test etwas wiederspricht)...



Genau das ist mein Dilemma. Ich muss öfters UnitTests für fremde Klassen schreiben, die ich meistens nicht verändern darf/will.
Sobald dort aber eine Methode enthalten ist, die selbstständig ein fremdes Objekt instantiiert, lässt sich kein "sauberer" bzw. "isolierter" UnitTest durchführen, da man dieses fremde Objekt nicht mocken kann.

Etwas naiv habe ich auf einen schönen Zaubertrick gehofft. ^^

Aber trotzdem danke für die Antwort.

Edit: 
Habe mir ein paar andere Frameworks fürs mocking angeschaut und PowerMock scheint
Konstruktoren mocken zu können.


----------

