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?
For Mockito, there is no direct support to mock private and static methods. In order to test private methods, you will need to refactor the code to change the access to protected (or package) and you will have to avoid static/final methods.
Method With No Arguments but With Return Value. As a simple example, let's mock the behavior of a private method with no arguments and force it to return the desired value: LuckyNumberGenerator mock = spy(new LuckyNumberGenerator()); when(mock, "getDefaultLuckyNumber"). thenReturn(300);
Since static method belongs to the class, there is no way in Mockito to mock static methods.
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/
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")); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With