2014-10-11 20 views
66

Viene visualizzata un'eccezione durante l'esecuzione dei test. Sto usando Mockito per deridere. I suggerimenti menzionati dalla libreria Mockito non aiutano.Rilevato stub non terminato in Mockito

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here: 
    -> at com.a.b.DomainTestFactory.myTest(DomainTestFactory.java:355) 

    E.g. thenReturn() may be missing. 
    Examples of correct stubbing: 
     when(mock.isOk()).thenReturn(true); 
     when(mock.isOk()).thenThrow(exception); 
     doThrow(exception).when(mock).someVoidMethod(); 
    Hints: 
    1. missing thenReturn() 
    2. you are trying to stub a final method, you naughty developer! 

     at a.b.DomainTestFactory.myTest(DomainTestFactory.java:276) 
     .......... 

Codice di prova da DomainTestFactory. Quando eseguo il seguente test, vedo l'eccezione

@Test 
public myTest(){ 
    MyMainModel mainModel = Mockito.mock(MyMainModel.class); 
    Mockito.when(mainModel.getList()).thenReturn(getSomeList()); --> Line 355 
} 

private List<SomeModel> getSomeList() { 
    SomeModel model = Mockito.mock(SomeModel.class); 
    Mockito.when(model.getName()).thenReturn("SomeName"); --> Line 276 
    Mockito.when(model.getAddress()).thenReturn("Address"); 
    return Arrays.asList(model); 
} 

public class SomeModel extends SomeInputModel{ 
    protected String address; 
    protected List<SomeClass> properties; 

    public SomeModel() { 
     this.Properties = new java.util.ArrayList<SomeClass>(); 
    } 

    public String getAddress() { 
     return this.address; 
    } 

} 

public class SomeInputModel{ 

    public NetworkInputModel() { 
     this.Properties = new java.util.ArrayList<SomeClass>(); 
    } 

    protected String Name; 
    protected List<SomeClass> properties; 

    public String getName() { 
     return this.Name; 
    } 

    public void setName(String value) { 
     this.Name = value; 
    } 
} 
+3

Quale linea è 355? – Mureinik

+0

Ciao Mureinik, ho aggiornato il post con i numeri di riga –

risposta

177

Stai annidando beffardo dentro di derisione. Stai chiamando getSomeList(), cosa che fa un po 'di derisione, prima che tu abbia finito il sdegno per MyMainModel. A Mockito non piace quando lo fai.

Sostituire

@Test 
public myTest(){ 
    MyMainModel mainModel = Mockito.mock(MyMainModel.class); 
    Mockito.when(mainModel.getList()).thenReturn(getSomeList()); --> Line 355 
} 

con

@Test 
public myTest(){ 
    MyMainModel mainModel = Mockito.mock(MyMainModel.class); 
    List<SomeModel> someModelList = getSomeList(); 
    Mockito.when(mainModel.getList()).thenReturn(someModelList); 
} 

Per capire perché questo causa un problema, è necessario conoscere un po 'su come funziona Mockito, e anche essere consapevoli in quale ordine le espressioni e le dichiarazioni sono valutato in Java.

Mockito non può leggere il codice sorgente, quindi per capire cosa si sta chiedendo di fare, si basa molto sullo stato statico. Quando chiami un metodo su un oggetto fittizio, Mockito registra i dettagli della chiamata in un elenco interno di invocazioni. Il metodo when legge l'ultima di queste chiamate dall'elenco e registra questa chiamata nell'oggetto OngoingStubbing restituito.

La linea

Mockito.when(mainModel.getList()).thenReturn(someModelList); 

provoca le seguenti interazioni con Mockito:

  • metodo Mock mainModel.getList() viene chiamato,
  • statico metodo when viene chiamato,
  • Metodo thenReturn viene chiamato sul OngoingStubbing oggetto restituito dal when me ThOD.

Procedimento thenReturn può quindi istruire il finto ha ricevuto tramite il metodo OngoingStubbing per gestire qualsiasi chiamata adatto al metodo getList per restituire someModelList.

Infatti, come Mockito non può vedere il tuo codice, è possibile anche scrivere il beffardo come segue:

mainModel.getList(); 
Mockito.when((List<SomeModel>)null).thenReturn(someModelList); 

Questo stile è un po 'meno chiaro da leggere, soprattutto perché in questo caso il null deve essere castato, ma genera la stessa sequenza di interazioni con Mockito e otterrà lo stesso risultato della riga precedente.

Tuttavia, la linea

Mockito.when(mainModel.getList()).thenReturn(getSomeList()); 

provoca i seguenti interazioni con Mockito:

  1. metodo Mock mainModel.getList() viene chiamato,
  2. statico metodo when viene chiamato,
  3. Una nuova mock di SomeModel creato (all'interno di getSomeList()),
  4. metodo Mock model.getName() viene chiamato,

A questo punto Mockito si confonde. Pensavo ti stessi prendendo in giro mainModel.getList(), ma ora stai dicendo che vuoi prendere in giro il metodo model.getName(). Per Mockito, sembra che si sta facendo quanto segue:

when(mainModel.getList()); 
// ... 
when(model.getName()).thenReturn(...); 

Questo sembra stupido Mockito in quanto non può essere sicuro di quello che stai facendo con mainModel.getList().

Si noti che non è stata effettuata la chiamata al metodo thenReturn, poiché la JVM deve valutare i parametri di questo metodo prima che possa chiamare il metodo. In questo caso, ciò significa chiamare il metodo getSomeList().

In genere, è una pessima decisione progettuale fare affidamento sullo stato statico, come fa Mockito, perché può portare a casi in cui il Principio di Least Astonishment viene violato. Tuttavia, il design di Mockito crea beffarde chiare ed espressive, anche se a volte porta a stupore.

Infine, le versioni recenti di Mockito aggiungono una riga in più al messaggio di errore sopra riportato. Questa linea in più indica che si può essere nella stessa situazione come questa domanda:

3: si stanno spegnendo il comportamento di un altro finto all'interno prima di istruzioni 'thenReturn' se completata

+0

Grazie Luca. Che ha funzionato –

+0

C'è qualche spiegazione di questo fatto? La soluzione funziona. E non capisco perché la creazione fittizia "sul posto" non funzioni. Quando crei il mock e passi il mock creato in riferimento ad altri finti, funziona. – Sergey

+0

Grazie per l'aggiornamento – Sergey

Problemi correlati