📜 ⬆️ ⬇️

PowerMock (+ Mockito) + TestNG and imitation of a call (mock) of static methods

On Habré, there was already an article with examples of using PowerMock, but it lacks such a description as imitation of calling static methods as independent “units” in a class, and in hybrid use, when a part of the static methods of a class is replaced with a “stub”, and some really called. I'll try to fix this niche.

First, create a demo class with static methods ( commit ):

public class ClassStatic { static String getValue() { return "value"; } static String getValue(final String s) { return getValue() + s; } } 


Let's add simple testing of static methods. To do this, create a class ClassStaticTest ( commit ):
 import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @Test(groups = {"static", "noMock"}) public class ClassStaticTest { @DataProvider public Object[][] data() throws Exception { return new Object[][]{{"", "value"}, {"test", "valuetest"}}; } @Test public void testGetValueVoid() throws Exception { Assert.assertEquals(ClassStatic.getValue(), "value"); } @Test(dataProvider = "data", dependsOnMethods = {"testGetValueVoid"}) public void testGetValueAttribute(final String v, final String r) throws Exception { Assert.assertEquals(ClassStatic.getValue(v), r); } } 

')
Up to this point, we have never used PowerMock, since we did not need it. Now, to make a “stub” for static methods, create the “backbone” of the test class:
 import org.powermock.modules.testng.PowerMockObjectFactory; import org.testng.IObjectFactory; import org.testng.annotations.ObjectFactory; import org.testng.annotations.Test; @Test(groups = {"static", "mock"}) public class ClassStaticMockTest { @ObjectFactory public IObjectFactory setObjectFactory() { return new PowerMockObjectFactory(); } } 
We created the class ClassStaticMockTest, in which we redefined the Object Factory for TestNG ( documentation )

Add a test with a “stub” for the static method:
 import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.testng.PowerMockObjectFactory; import org.testng.Assert; import org.testng.IObjectFactory; import org.testng.annotations.DataProvider; import org.testng.annotations.ObjectFactory; import org.testng.annotations.Test; import static org.mockito.MockitoAnnotations.Mock; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.when; @Test(groups = {"static", "mock"}) @PrepareForTest({ClassStatic.class}) public class ClassStaticMockTest { @Mock public ClassStatic classStatic; @DataProvider public Object[][] data() throws Exception { return new Object[][]{{"", "newValue"}, {"test", "newValuetest"}}; } @ObjectFactory public IObjectFactory setObjectFactory() { return new PowerMockObjectFactory(); } @Test(dependsOnGroups = {"noMock"}) public void mockGetValueVoid() throws Exception { mockStatic(ClassStatic.class); when(ClassStatic.getValue()).thenReturn("newValue"); Assert.assertEquals(ClassStatic.getValue(), "newValue"); } } 


The final “chord” remains - a hybrid test in which the call of one static method is blocked by a “stub”, and for the other a real call is made ( commit ):
 import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.testng.PowerMockObjectFactory; import org.testng.Assert; import org.testng.IObjectFactory; import org.testng.annotations.DataProvider; import org.testng.annotations.ObjectFactory; import org.testng.annotations.Test; import static org.mockito.MockitoAnnotations.Mock; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.when; /** Created by borz on 06.07.13. */ @Test(groups = {"static", "mock"}) @PrepareForTest({ClassStatic.class}) public class ClassStaticMockTest { @Mock public ClassStatic classStatic; @DataProvider public Object[][] data() throws Exception { return new Object[][]{{"", "newValue"}, {"test", "newValuetest"}}; } @ObjectFactory public IObjectFactory setObjectFactory() { return new PowerMockObjectFactory(); } @Test(dependsOnGroups = {"noMock"}) public void mockGetValueVoid() throws Exception { mockStatic(ClassStatic.class); when(ClassStatic.getValue()).thenReturn("newValue"); Assert.assertEquals(ClassStatic.getValue(), "newValue"); } @Test(dataProvider = "data", dependsOnMethods = {"mockGetValueVoid"}) public void testGetValueAttribute(final String v, final String r) throws Exception { mockStatic(ClassStatic.class); when(ClassStatic.getValue()).thenReturn("newValue"); when(ClassStatic.getValue(v)).thenCallRealMethod(); Assert.assertEquals(ClassStatic.getValue(v), r); } } 
We override the getValue() method call and indicate that when the getValue(String value) call is called, the actual method of the class that already calls getValue() inside itself will be called.

As a “life” example of the need to use imitation of calling static methods is the “overlapping” of these methods by “stubs” when testing other classes / methods ( commit ).

Add a class that uses the static method ClassStatic.getValue() :
 public class ClassUseStatic { public String getValue() { return ClassStatic.getValue() + "noStatic"; } } 


And we add a test for the ClassUseStatic.getValue() method with overriding the call ClassStatic.getValue() :
 import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.testng.PowerMockObjectFactory; import org.testng.Assert; import org.testng.IObjectFactory; import org.testng.annotations.DataProvider; import org.testng.annotations.ObjectFactory; import org.testng.annotations.Test; import static org.mockito.MockitoAnnotations.Mock; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.when; @Test(groups = {"useStatic", "mock"}, dependsOnGroups = {"static"}) @PrepareForTest({ClassStatic.class}) public class ClassUseStaticTest { @Mock public ClassStatic classStatic; @DataProvider public Object[][] data() throws Exception { return new Object[][]{{"newValue1", "newValue1noStatic"}, {"newValue2", "newValue2noStatic"}}; } @ObjectFactory public IObjectFactory setObjectFactory() { return new PowerMockObjectFactory(); } @Test(dataProvider = "data") public void testGetValue(String value, String result) throws Exception { mockStatic(ClassStatic.class); when(ClassStatic.getValue()).thenReturn(value); ClassUseStatic testClass = new ClassUseStatic(); Assert.assertEquals(result, testClass.getValue()); } } 


PS: All examples can be found on GitHub .

UPD: added an example of simulating a call to static methods when testing "normal" classes.

Source: https://habr.com/ru/post/185834/


All Articles