Testen von void Methoden mit PowerMockito

Arbeite mich gerade in das Testen mit gemockten Objekten ein. Vielleicht kann mir jemand die Frage beantworten. Wie teste ich mit Powermockito die Argumente von void-methoden?

Beispiel:


    private final Logger logger = Logger.getRootLogger();
    private final ResourceBundle messages = PropertyResourceBundle.getBundle("res.messages", new Locale("en"));
    
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        logger.error(messages.getString("error.exception.uncaught"));
        logger.info(e);
    }

}```

Weiter bin ich bisher leider noch nicht gekommen:
```@Test
    public void testUncaughtException() {
       UncaughtExcHandler ue=new UncaughtExcHandler();
       UncaughtExcHandler spy=PowerMockito.spy(ue);
       
    }```

Bekomme ich das mit when...then... hin oder wie würdet ihr das umsetzen?

Die Frage ist, welches verhalten der Metrhode willst Du denn Testen?

Ich vermute mal, Du willst testen, dass die richtige Loggerausgabe gemacht wird.
In dem Fall würde ich das Logger-Objekt mocken und darauf Prüfen, welche Parameter es bekommen hat:
[SPOILER]```@Test
public void testUncaughtException_withThrowable_passesToLogger(){
Logger logger = mock(Logger.class);
Throwable throwable = mock(Throwable);
UncaughtExcHandler ue=new UncaughtExcHandler(loggerMock);

ue.uncaughtException(null, throwable);

    ArgumentCaptor<Throwable> theError = ArgumentCaptor.forClass(Throwable.class);
    verify(logger).info(theError.capture());
    assertTrue("throwable passed", throwable =theError.getValue());

}

@Test
public void testUncaughtException_withThrowable_localizedErrormessage(){
Logger logger = mock(Logger.class);
Throwable throwable = mock(Throwable);
UncaughtExcHandler ue=new UncaughtExcHandler(loggerMock);

ue.uncaughtException(null, throwable);

    ArgumentCaptor<String> theErrorMessage = ArgumentCaptor.forClass(String.class);
    verify(logger).error(theErrorMessage.capture());
    assertEquals("localizes message", "Was immer in Deiner Properties-Datei steht", theErrorMessage.getValue());

}```[/SPOILER]
Und dass geht sogar rein mit Mockito, ganz ohne Power…

bye
TT

Guter Tip soweit,
ich glaube nur ich benötige doch Powermock um den Logger im ‘ue’ Objekt zu setzen
...UncaughtExcHandler ue=new UncaughtExcHandler(loggerMock);...
Das funktioniert nämlich nicht so einfach

Die Lösung dafür hieße “Dependency-Injection”. Übergib den Logger im Konstruktor der Produktiv-Klasse…

bye
TT

Ich wuerde aber davon absehen nun jeder Klasse, die einen Logger hat nun diesen per Konstruktor zu injezieren.

Man kann doch bestimmt den Logger so in den Tests initialisieren, dass diese so arbeitet, dass man zugriff darauf hat ?!

[quote=bygones]ch wuerde aber davon absehen nun jeder Klasse, die einen Logger hat nun diesen per Konstruktor zu injezieren.[/quote]Warum?
DI ist ganz allgemein eine als sinvoll erachtete Methode, warum soll man für Logger hier eine Ausnahme machen?
Und streng genommen muss man ja auch in jeder Klasse, die loggt auch testen, dass sie das Richtige ausgibt, womit man ja das Problem sowieso mit jeder dieser Klassen hätte…

Und wenn man dann auch noch eines der DI-Frameworks einsetzt hat man womöglich gar kein Problem mehr…

bye
TT

So streng sehe ich das nicht. Ich teste die Logausgaben nicht. Wenn da was schiefläuft, ist das meistens nicht soo schlimm. Diese Abhängigkeit zu injizieren macht den benutzenden Code nur hässlicher. Zumal der Logger auch klassenspezifisch konfiguriert wird.
Wenn ich also an verschiedenen Stellen Instanzen erzeuge (warum auch immer), dann müsste ich an jeder Stelle das selbe (z. B. LoggerFactory.getLogger(MyClass.class)) injizieren, was dem DRY-Prinzip widerspricht, statt eine Zeile in der Klasse zu schreiben (dank Live-Template sind das bei mir genau 4 Tastendrücke):
private final Logger log = LoggerFactory.getLogger(MyClass.class);

Wenn man die Logausgaben nicht testet, dann hat man auch keine Probleme mit Mocking.

[quote=cmrudolph]Wenn ich also an verschiedenen Stellen Instanzen erzeuge (warum auch immer), dann müsste ich an jeder Stelle das selbe (z. B. LoggerFactory.getLogger(MyClass.class)) injizieren, was dem DRY-Prinzip[/quote]es sei den, Du übergibst eine eigene LoggerFactory, bei der getLogger(MyClass.class); eben nicht static ist, dann kann man über deren Mock Logger-Mocks einstreuen. Dieser Verstoß gegen das “Law of Demeter” wäre IMHO tolerierbar.

[quote=cmrudolph;101761]Wenn man die Logausgaben nicht testet, dann hat man auch keine Probleme mit Mocking.[/quote]wohl war.

bye
TT

[QUOTE=Timothy_Truckle;101764]es sei den, Du übergibst eine eigene LoggerFactory, bei der getLogger(MyClass.class); eben nicht static ist, dann kann man über deren Mock Logger-Mocks einstreuen.[/QUOTE]Das ist richtig. Wenn ich das richtig sehe, könnte man das mit slf4j sogar so machen, indem man eine ILoggerFactory übergibt. Das wäre zwar erst einmal ungewohnt, aber sicherlich praktikabel. Im aufrufenden Code dann jeweils LoggerFactory.getILoggerFactory() stehen zu haben, könnte man als Boilerplate abtun. Im Gegenzug erhält man hervorragende Testbarkeit und vermeidet die Codeduplikation bestmöglich.
Wenn man mit einem Setter für die Factory arbeitet und eine Defaultimplementierung wählt (eben die oben genannte), dann kann man die Duplikation sogar noch weiter reduzieren.

[QUOTE=Timothy_Truckle;101764]wohl war.[/QUOTE]Ich gebe zu, das klang jetzt ziemlich blöd, weil so offensichtlich. Was ich damit sagen wollte war, dass es eben darauf ankommt, ob man in diesem Fall bereit ist, Kompromisse einzugehen oder nicht.