2012-03-15 10 views
23

Dagli esempi sul PowerMock homepage, vedo il seguente esempio per parte beffardo un metodo privato con Mockito:È possibile utilizzare il mocking parziale per i metodi statici privati ​​in PowerMock?

@RunWith(PowerMockRunner.class) 
// We prepare PartialMockClass for test because it's final or we need to mock private or static methods 
@PrepareForTest(PartialMockClass.class) 
public class YourTestCase { 
@Test 
public void privatePartialMockingWithPowerMock() {   
    PartialMockClass classUnderTest = PowerMockito.spy(new PartialMockClass()); 

    // use PowerMockito to set up your expectation 
    PowerMockito.doReturn(value).when(classUnderTest, "methodToMock", "parameter1"); 

    // execute your test 
    classUnderTest.execute(); 

    // Use PowerMockito.verify() to verify result 
    PowerMockito.verifyPrivate(classUnderTest, times(2)).invoke("methodToMock", "parameter1"); 
} 

Tuttavia, questo approccio non sembra funzionare quando il metodo privato che vogliamo prendere in giro è statico. Vorrei creare un mock parziale della classe inferiore, con il metodo readFile deriso:

package org.rich.powermockexample; 

import java.io.File; 
import java.io.IOException; 
import java.nio.charset.Charset; 
import java.util.List; 

import static com.google.common.io.Files.readLines; 

public class DataProvider { 

    public static List<String> getData() { 
     List<String> data = null; 
     try { 
      data = readFile(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     return data; 
    } 

    private static List<String> readFile() throws IOException { 
     File file = new File("/some/path/to/file"); 
     List<String> lines = readLines(file, Charset.forName("utf-8")); 
     return lines; 
    } 

} 

Si prega di qualcuno potrebbe farmi sapere come questo può essere realizzato?

+0

Perché, esattamente? In altre parole, cosa non puoi simulare prendendo in giro solo getData? –

+0

Potrei - ma volevo vedere se è possibile gestire i metodi statici privati ​​in una simulazione parziale con PowerMock. –

+0

Oh. Dovrei cercare la meccanica, ma AFAIK sì, tramite la manipolazione del codice byte, allo stesso modo in cui puoi, ad esempio, prendere in giro o sostituire un costruttore. –

risposta

29

Dopo aver fatto un po 'più di ricerca, sembra che PowerMockito.spy() e PowerMockito.doReturn() sono ciò che è richiesto qui:

package com.richashworth.powermockexample; 

import org.junit.Before; 
import org.junit.BeforeClass; 
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; 

import java.util.ArrayList; 
import java.util.List; 

import static org.junit.Assert.assertEquals; 


@RunWith(PowerMockRunner.class) 
@PrepareForTest({DataProvider.class}) 
public class ResultsWriterTest { 

    private static List<String> mockData = new ArrayList<String>(); 
    private ResultsWriter resultsWriter; 

    @BeforeClass 
    public static void setUpOnce() { 
     final String firstLine = "Line 1"; 
     final String secondLine = "Line 2"; 
     mockData.add(firstLine); 
     mockData.add(secondLine); 
    } 

    @Before 
    public void setUp() { 
     resultsWriter = new ResultsWriter(); 
    } 

    @Test 
    public void testGetDataAsString() throws Exception { 
     PowerMockito.spy(DataProvider.class); 
     PowerMockito.doReturn(mockData).when(DataProvider.class, "readFile"); 

     final String expectedData = "Line 1\nLine 2\n"; 
     final String returnedString = resultsWriter.getDataAsString(); 

     assertEquals(expectedData, returnedString); 
    } 

} 
+1

Per l'elenco completo del codice per questo esempio, controlla il post del mio blog [qui] (http://richardashworth.blogspot.com/2012/03/turbocharge-your-mocking-framework-with.html) –

+4

1+: Beautiful rispondi, amico. Funziona come un fascino. Nemmeno il sito Web PowerMock ha descritto così bene come hai fatto tu. – acdcjunior

+2

Meraviglioso! Esattamente quello di cui avevo bisogno. Grazie !! –

1

In generale, utilizzare solo la derisione statica per le classi fuori dal proprio controllo (ad esempio java.io.File). Dal DataProvider e dal readFile siete il vostro refactoring DataProvider in una classe appropriata (cioè rendete i suoi metodi non statici), estraete readFile in un oggetto helper e poi prendetene un mock. Vedi questa risposta https://stackoverflow.com/a/8819339/116509.

+0

Ciao, grazie per la risposta. Sono d'accordo sul fatto che questo esempio sia un po 'forzato, ma l'ho messo insieme per esplorare cosa è capace di PowerMock piuttosto che per risolvere un particolare problema. Stai dicendo che semplicemente non è possibile usare PowerMock qui? –

+0

Non lo so, ma secondo la mia esperienza, se stai prendendo in giro metodi statici privati ​​sulle tue classi, probabilmente stai facendo qualcosa di sbagliato. – artbristol

5
classe

prova:

@RunWith(PowerMockRunner.class) 
@PrepareForTest(DataProvider.class) 
public class DataProviderTest { 

    @Test 
    public void testGetDataWithMockedRead() throws Exception { 
     mockStaticPartial(DataProvider.class, "readFile"); 

     Method[] methods = MemberMatcher.methods(DataProvider.class, "readFile"); 
     expectPrivate(DataProvider.class, methods[0]).andReturn(Arrays.asList("ohai", "kthxbye")); 
     replay(DataProvider.class); 

     List<String> theData = DataProvider.getData(); 
     assertEquals("ohai", theData.get(0)); 
     assertEquals("kthxbye", theData.get(1)); 
    } 

} 

classe in fase di sperimentazione (in pratica il vostro):

public class DataProvider { 

    public static List<String> getData() { 
     try { 
      return readFile(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
      return null; 
     } 
    } 

    private static List<String> readFile() throws IOException { 
     File file = new File("/some/path/to/file"); 
     return readLines(file, Charset.forName("utf-8")); 
    } 

} 
+0

Ah, grazie. Sembra che faccia quello che sto cercando. Però non ho trovato il metodo mockStaticPartial nell'api - stavi usando powermock-mockito per questo, o è nel ramo di easymock? –

+1

Dal changelog, vedo: "* Rimosso mockStatic (classe tipo, metodo metodo, metodo ... metodi), mockStaticPartial, mockPartial, mock (classe tipo, metodo ... metodi) & mock (classe tipo, Metodo ... metodi) dall'API di estensione Mockito. Dovresti invece utilizzare PowerMockito.spy. " Dato che stiamo cercando di simulare un metodo statico, non riesco a vedere come questo possa essere fatto se un'istanza della classe sotto test viene data al metodo spy(). –

+0

@RichAshworth EasyMock, ma potrebbe non avere importanza. –