2012-11-20 17 views
9

Ich verspotte ein Objekt mit Mockito, die gleiche Methode für dieses Objekt wird mehrmals aufgerufen und ich möchte jedes Mal den gleichen Wert zurückgeben.
Das ist, was ich habe:Mockito: mehrere Aufrufe an die gleiche Methode

LogEntry entry = null; // this is a field 
// This method is called once only. 
when(mockLogger.createNewLogEntry()).thenAnswer(new Answer<LogEntry>() { 
    @Override 
    public LogEntry answer(InvocationOnMock invocationOnMock) throws Throwable { 
    entry = new LogEntry(); 
    return entry; 
    } 
}); 
// This method can be called multiple times, 
// If called after createNewLogEntry() - should return initialized entry. 
// If called before createNewLogEntry() - should return null. 
when(mockLogger.getLogEntry()).thenAnswer(new Answer<LogEntry>() { 
    @Override 
    public LogEntry answer(InvocationOnMock invocationOnMock) throws Throwable { 
    return entry; 
    } 
}); 

Das Problem ist, wie es scheint, dass meine getLogEntry Methode nur einmal aufgerufen wird. Für alle folgenden Aufrufe wird stattdessen null zurückgegeben und ich erhalte NPEs in Tests.
Wie kann ich spotten, stubbed Version für alle Anrufe zu verwenden?

============================================== ===================
Post mortem für zukünftige Generationen

habe ich einige zusätzliche Untersuchung und wie immer ist es nicht Bibliothek Fehler, ist es meine Schuld . In meinem Code eine der Methoden getLogEntry() vor dem Aufruf createNewLogEntry() aufgerufen. NPE war absolut legitim, der Test hat tatsächlich einen Fehler in meinem Code gefunden, nicht dass ich einen Fehler in Mockito gefunden habe.

+0

Ziemlich mysteriös. Dies sollte generell funktionieren. Ich schätze, ich würde da ein paar Fragen stellen: 1) Bist du sicher, dass es der Eintrag ist, der null ist und nicht auf irgendeine Weise, dass mockLogger irgendwo auf null zurückgesetzt wird? 2) Ist es möglich, dass mockLogger ohne die verspotteten Methoden neu erstellt wird? Es kann hilfreich sein, den obigen Code in den Methoden zu definieren, die ihn definieren (Setup vs. Testmethode). Schließlich könnten Sie eine println in Ihren Antwort-Impls (oder Breakpoints) versuchen, nur um sicher zu sein, was tatsächlich ausgeführt wird. –

+0

Versucht, Ihr Problem zu reproduzieren, ein ähnlicher Ansatz funktioniert für mich mit Mockito 1.9.5 ==> vielleicht können Sie den Code der gesamten Test-Klasse über die Mockito Mailing-Liste senden? – s106mo

Antwort

10

Ihr Stub sollte funktionieren, wie Sie es wollen. Von Mockito doc:

Sobald stubbed wird das Verfahren immer stubbed Wert zurückgeben, unabhängig , wie oft sie aufgerufen wird.

+0

Ich habe die Frage korrigiert, ich benutze thenAnswer(). –

1

Fehle ich etwas, oder würde Folgendes genügen?

LogEntry entry = null; // this is a field 
when(mockLogger.createNewLogEntry()).thenAnswer(new Answer<LogEntry>() { 
    @Override 
    public LogEntry answer(InvocationOnMock invocationOnMock) throws Throwable { 
    if (entry == null) { 
     entry = new LogEntry(); 
    } 
    return entry; 
    } 
}); 
when(mockLogger.getLogEntry()).thenAnswer(new Answer<LogEntry>() { 
    @Override 
    public LogEntry answer(InvocationOnMock invocationOnMock) throws Throwable { 
    return entry; 
    } 
}); 

Nur die Zuweisung tun, wenn entry == null.

+0

createNewLogEntry() wird nur einmal aufgerufen. Danach kann getLogEntry() mehrere Male aufgerufen werden, aber es scheint, dass die gespottete Version nur einmal aufgerufen wird, nachdem der Standardwert null zurückgegeben wurde. –

+2

Scheint, als ob etwas Seltsames vor sich geht. Mockito sollte und ruft die Antwort jedes Mal auf, wenn die Methode aufgerufen wird. Sind Sie sicher, dass Sie den Schein oder Eintrag nicht irgendwo in Ihrem Code/Test zurücksetzen? –

+0

Ich habe überprüft, die einzige Stelle, die ich gesetzt habe Eintrag = Null ist in SetUp() -Methode wie oben gezeigt. Ich setze es nirgendwo im Test zurück. Ich werde etwas mehr Debugging machen, aber soweit ich das beurteilen kann, wird Answer for getLogEntry() nur einmal aufgerufen. Ich werde morgen mehr untersuchen. –

4

Es sei denn, ich bin etwas fehlt, wenn Sie das gleiche Objekt für jeden Methodenaufruf, warum dann nicht einfach do zurückkehren wollen:

final LogEntry entry = new LogEntry() 
when(mockLogger.createNewLogEntry()).thenReturn(entry); 
when(mockLogger.getLogEntry()).thenReturn(entry); 

... 

verify(mockLogger).createNewLogEntry(); 
verify(mockLogger, times(???)).getLogEntry(); 

Mockito wird wieder den gleichen Wert für jeden passenden Anruf.

+0

Wenn createNewLogEntry() zuerst aufgerufen wird, sollten alle nachfolgenden Aufrufe von getLogEntry() den initialisierten Eintrag zurückgeben.Wenn createNewLogEntry() NICHT zuerst aufgerufen wird, sollten alle nachfolgenden Aufrufe von getLogEntry() null zurückgeben. Was Sie vorgeschlagen haben, wird nicht so funktionieren. –

+1

Wenn möglich, können Sie dies in zwei separate Testfälle aufteilen? Eine, wo 'createNewLogEntry' als die andere aufgerufen wird, wenn es nicht ist? Das könnte die Dinge vereinfachen. – Jonathan

+1

Ich glaube, du meinst 'thenReturn', nicht' thenAnswer'. –

Verwandte Themen