2012-11-20 13 views
17

Ho una classe DummyResource e un file DummyTarget e una classe di test TestDummyResource come sotto, ma l'oggetto mocked DummyResource dr = mock(DummyResource.class) funziona solo quando chiamo il costruttore all'interno di una classe normale , quando viene chiamato in una classe anonima, chiama il vero costruttore invece di usare l'oggetto deriso.costruttore di mocking di powermock via whennew() non funziona con la classe anonima

Versioni:

powermock 1.4.12 Mockito 1.9.0 JUnit 4.8.2

DummyTarget.java:

import java.io.IOException; 
import java.io.OutputStream; 

import javax.ws.rs.WebApplicationException; 
import javax.ws.rs.core.StreamingOutput; 


public class DummyTarget { 
    public StreamingOutput testMocking() { 
     return new StreamingOutput() { 
      @Override 
      public void write(OutputStream arg0) throws IOException, WebApplicationException { 
       new DummyResource(); 
      } 
     }; 
    } 
} 

DummyResource.java:

package com.smin.dummy; 

public class DummyResource { 
    public DummyResource() { 
     System.out.println("mock failure"); 
    } 
} 

TestDummyResource.java:

package com.smin.dummy; 

import static org.mockito.Mockito.mock; 

import java.io.IOException; 

import javax.ws.rs.WebApplicationException; 
import javax.ws.rs.core.StreamingOutput; 

import org.junit.Before; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.powermock.api.mockito.PowerMockito; 
import org.powermock.core.classloader.annotations.PrepareForTest; 
import org.powermock.modules.junit4.PowerMockRunner; 

@RunWith(PowerMockRunner.class) 
@PrepareForTest({DummyResource.class,DummyTarget.class}) 
public class TestDummyResource { 

    @Before 
    public void setUp() throws Exception { 
     DummyResource dr = mock(DummyResource.class); 
     PowerMockito.whenNew(DummyResource.class).withNoArguments().thenReturn(dr); 
    } 

    @Test 
    public void testMocked() throws WebApplicationException, IOException { 
     new DummyResource(); // it uses the mocked object dr here, 
          //doesn't print "mock failure" 
     StreamingOutput sop = new DummyTarget().testMocking(); 
     sop.write(null);  // it calls DummyResource's constructor, 
          // prints ""mock failure"" here 
    } 
} 

risposta

10

Sembra che una classe anonima possa ereditare il pacchetto della classe che lo definisce. Si può provare il modulo jolly di PrepareForTest:?

@PrepareForTest("com.smin.dummy.*") 

Se questo non dovesse funzionare, si potrebbe provare il fucile PrepareEverythingForTest annotazione.

+1

PrepareEverythingForTest impiega anni per essere eseguito. – Shengjie

+2

Perfetto, tranne che l'API potrebbe essere cambiata da questo post. Usa '@PrepareForTest (fullyQualifiedNames =" com.smin.dummy. * ")' –

+0

@Brian Il collegamento è ** morto ** –

31

È necessario aver preparato la classe chiamando il costruttore, non la classe su cui è chiamato il costruttore, il seguente dovrebbe fissare in su:

@PrepareForTest(DummyTarget.class) 

Per ulteriori informazioni, consultare la pagina this.

+0

mio caso in realtà è più complesso, il costruttore è chiamato in una classe anonima in cui nemmeno la la classe anonima dichiarata in @PrepareForTest non funziona ancora. – Shengjie

+0

Questo è brutto, non sono sicuro che sia possibile (usando PowerMock) prendere in giro il costruttore in una classe anonima. Se puoi cambiare la fonte potresti essere in grado di farlo funzionare se lo cambi in una classe privata. – zbrunson

+0

Ho aggiornato il mio codice sopra, c'è qualche soluzione se il costruttore viene chiamato nella classe anonima? – Shengjie

8

In realtà, è necessario preparare per testare la classe che effettua la chiamata del costruttore, non la classe su cui è stato chiamato il costruttore. Vedi https://github.com/jayway/powermock/wiki/MockConstructor.

Nel tuo caso, si dovrebbe usare @PrepareForTest (DummyTarget.class)

+2

Questa è la risposta corretta, non quella sopra. – user590849

+0

Ha funzionato per me. Grazie. – defactodeity

0

Ho avuto lo stesso problema e risolto con usando whenNew con nome completo. Il nome completo di una classe anonima interna nel tuo caso è:

DummyTarget.class + "$1" 

così si dovrebbe creare un modello di quella classe:

DummyResource dr = mock(Class.forName(DummyTarget.class + "$1")); 

e lavorerà per voi.

Inoltre, non dimenticare di preparare la classe DummyTarget:

@PrepareForTest(DummyTarget.class) 

Speranza ha aiutato =]

+0

Parzialmente lavorato. Sono in grado di creare un oggetto fittizio di classe anonima. Anche in grado di collegarlo con il codice effettivo. Ma l'oggetto è sempre nullo. –

Problemi correlati