26

From the examples on the PowerMock homepage, I see the following example for partially mocking a private method with Mockito:

@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");
}

However, this approach does not seem to work when the private method we wish to mock is static. I wish to create a partial mock of the below class, with the readFile method mocked:

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;
    }

}

Please could someone let me know how this can be achieved?

Rich Ashworth
  • 1,995
  • 4
  • 19
  • 29

3 Answers3

36

After doing a bit more research, it seems that PowerMockito.spy() and PowerMockito.doReturn() are what is required here:

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);
    }

}

For further details and the complete code listing, check out my blog post here: https://richashworth.com/post/turbocharge-your-mocking-framework-with-powermock/

Moffee
  • 401
  • 5
  • 15
Rich Ashworth
  • 1,995
  • 4
  • 19
  • 29
6

Test class:

@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));
    }

}

Class being tested (basically yours):

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"));
    }

}
Dave Newton
  • 158,873
  • 26
  • 254
  • 302
  • Ah, thanks. That looks like it does what I'm looking for. I didn't find the mockStaticPartial method in the api though - were you using powermock-mockito for this, or is this in the easymock branch? – Rich Ashworth Mar 15 '12 at 15:11
  • 2
    From the changelogs, I see: "* Removed mockStatic(Class> type, Method method, Method... methods), mockStaticPartial, mockPartial, mock(Class type, Method... methods) & mock(Class type, Method... methods) from the Mockito extension API. You should use PowerMockito.spy instead." As we are trying to mock a static method, I can't see how this can be done if an instance of the class under test is given to the spy() method. – Rich Ashworth Mar 15 '12 at 15:16
  • @RichAshworth EasyMock, but may not matter. – Dave Newton Mar 15 '12 at 15:16
  • Ok. Thanks for the help. This certainly works with the EasyMock fork. Thinkg I've found an approach that works with the Mockito version - will post the solution as an alternative answer. – Rich Ashworth Mar 15 '12 at 15:25
3

In general, only use static mocking for classes that are beyond your control (e.g. java.io.File). Since DataProvider and readFile are your own, refactor DataProvider into a proper class (i.e. make its methods non-static), pull out readFile into a helper object and then mock that. See this answer https://stackoverflow.com/a/8819339/116509.

Community
  • 1
  • 1
artbristol
  • 32,010
  • 5
  • 70
  • 103
  • Hi, Thanks for the response. I agree that this example is a little contrived, but I put it together to explore what PowerMock is capable of rather than to solve a particular problem. Are you saying that it simply isn't possible to use PowerMock here? – Rich Ashworth Mar 15 '12 at 13:07
  • 1
    I don't know but in my experience, if you're mocking private static methods on your own classes, you're probably doing something wrong. – artbristol Mar 15 '12 at 13:09