2013-04-11 11 views
18

Non sono sicuro su come prendere in giro una classe enum singleton.Come prendere in giro una classe enum singleton usando Mockito/Powermock?

public enum SingletonObject{ 
    INSTANCE; 
    private int num; 

    protected setNum(int num) { 
    this.num = num; 
    } 

    public int getNum() { 
    return num; 
    } 

vorrei stub getNum() nell'esempio di cui sopra, ma non riesco a capire come per deridere la classe SingletonObject vero e proprio. Pensavo che usare Powermock per preparare il test sarebbe stato d'aiuto dato che le enumerazioni sono intrinsecamente definitive.

//... rest of test code 
@Test 
public void test() { 
    PowerMockito.mock(SingletonObject.class); 
    when(SingletonObject.INSTANCE.getNum()).thenReturn(1); //does not work 
} 

Questo utilizza PowerMockMockito 1.4.10 e Mockito 1.8.5.

+0

Verificare thread simile: http://stackoverflow.com/questions/2302179/mocking-a-singleton-class –

+0

Grazie Martin, ho letto attraverso quel thread e sembra un approccio per utilizzare il modo non enum di implementando un singleton, e sono in grado di usare correttamente il mocking con quel metodo. Tuttavia, c'è un modo per deridere una classe enum singleton? Da quello che ho raccolto, la classe enum singleton è il metodo raccomandato per dichiarare un singleton dopo java 1.5. –

+0

[Re: PowerMock: posso prendere in giro le enumerazioni?] (Https://groups.google.com/forum/?fromgroups=#!topic/powermock/hqrJaMi0Zrc) – Joe

risposta

23

Se si desidera eliminare ciò che INSTANCE restituisce, è possibile farlo ma è un po 'brutto (utilizzando la manipolazione del codice byte riflessione &). Ho creato & testato un semplice progetto con tre classi utilizzando PowerMock 1.4.12/Mockito 1.9.0. Tutte le classi erano nello stesso pacchetto.

SingletonObject.java

public enum SingletonObject { 
    INSTANCE; 
    private int num; 

    protected void setNum(int num) { 
     this.num = num; 
    } 

    public int getNum() { 
     return num; 
    } 
} 

SingletonConsumer.java

public class SingletonConsumer { 
    public String consumeSingletonObject() { 
     return String.valueOf(SingletonObject.INSTANCE.getNum()); 
    } 
} 

SingletonConsumerTest.java

import static org.junit.Assert.*; 
import static org.powermock.api.mockito.PowerMockito.*; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.powermock.core.classloader.annotations.PrepareForTest; 
import org.powermock.modules.junit4.PowerMockRunner; 
import org.powermock.reflect.Whitebox; 

@RunWith(PowerMockRunner.class) 
@PrepareForTest({SingletonObject.class}) 
public class SingletonConsumerTest { 
    @Test 
    public void testConsumeSingletonObject() throws Exception { 
     SingletonObject mockInstance = mock(SingletonObject.class); 
     Whitebox.setInternalState(SingletonObject.class, "INSTANCE", mockInstance); 

     when(mockInstance.getNum()).thenReturn(42); 

     assertEquals("42", new SingletonConsumer().consumeSingletonObject()); 
    } 
} 

La chiamata al Whitebox.setInternalState sostituisce INSTANCE con un oggetto fittizio che è possibile manipolare all'interno il tuo test.

+1

Ma come puoi prendere in giro SingletonObject. classe? Fornirà MockitoException con commento "Mockito non può simulare/spia seguenti: - classi finali - classi anonime - tipi primitivi" – Thamiar

+1

Questo utilizza PowerMock. –

+0

Ciao, ho ottenuto 'java.lang.IllegalAccessException: Impossibile impostare static final' mentre si utilizza' Whitebox.setInternalState'. Sai perché? – elsennov