The previous two articles covered JUnit and Mockito, one for assertions and one for simulating our non-test classes. PowerMock extends the Mockito framework to support Mock Static methods, private methods, final methods, classes, and more. Why didn’t Mockito support the private method itself? Find out why if you are interested)

1. PowerMock choice

PowerMock mainly revolves around Junit and TestNg testing frameworks. In Android, we often use Junit + Mockito + PowerMock. Since PowerMock is an extension of Mockito, we need to find a supported version of PowerMock to use.

Here we use the corresponding version as follows:

TestCompile "org.mockito:mockito-core:2.8.9" testCompile "org. powerMock :powermock-module-junit4:1.7.3" testCompile "Org. Powermock: powermock - module - junit 4 - rule: 1.7.3" testCompile "org. Powermock: powermock - API - mockito2:1.7.3." " Mockito2 testCompile "org.powermock:powermock-classloading-xstream:1.7.3"Copy the code

2. PowerMock use

First we define a Fruit class, and Banana inherits from it. There are static, private, and so on, which we’ll mock later.

Class Fruit {private String Fruit = "Fruit "; public String getFruit() { return fruit; }}Copy the code
Public class Banana extends Fruit{private static String COLOR = "yellow "; public Banana() {} public static String getColor() { return COLOR; } public String getBananaInfo() { return flavor() + getColor(); } private String flavor() {return "flavor "; } public final boolean isLike() { return true; }}Copy the code

Mock static methods

@RunWith(PowerMockRunner.class) public class PowerMockitoStaticMethodTest { @Test @PrepareForTest({Banana.class}) public  void testStaticMethod() { PowerMockito.mockStatic(Banana.class); //<-- mock static class mockito.when (banana.getcolor ()).thenreturn (" green "); Assert.assertequals (" green ", banana.getColor ()); assert.assertequals (" green ", banana.getcolor ()); }}Copy the code

To first use PowerMock, you must annotate @prepareForTest and @runwith (PowerMockRunner. Class). The annotation @prepareForTest writes the class of the static method.

If we want to change the class’s private static constant, such as COLOR in Banana.

@Test @PrepareForTest({Banana.class}) public void testChangeColor() { Whitebox.setInternalState(Banana.class, "COLOR", "Red "); AssertEquals (" red ", banana.getcolor ()); assert.assertequals (" red ", banana.getcolor ()); }Copy the code

Mock private methods

@RunWith(PowerMockRunner.class) public class PowerMockitoPrivateMethodTest { @Test @PrepareForTest({Banana.class}) public void testPrivateMethod() throws Exception { Banana mBanana = PowerMockito.mock(Banana.class); PowerMockito.when(mBanana.getBananaInfo()).thenCallRealMethod(); Powermockito. when(mBanana, "flavor"). ThenReturn (" bitter "); Assert.assertequals (" bitter yellow ", mbanana.getbananainfo ()); assert.assertequals (" bitter yellow ", mbanana.getbananainfo ()); / / verification. The flavor is called a PowerMockito verifyPrivate (mBanana) invoke (" flavor "); }}Copy the code

We mock the private method Flavor to change the “sweet” to “bitter.” Of course, we can also skip private methods, the code is as follows:

@Test @PrepareForTest({Banana.class}) public void skipPrivateMethod() { Banana mBanana = new Banana(); // override flavor method powermockito.suppress (powermockito.method (banana.class, "flavor")); Assert.assertequals ("null yellow ", mbanana.getBananainfo ()); assert.assertequals ("null yellow ", mbanana.getBananainfo ()); }Copy the code

Because the flavor method was skipped, the final output is null yellow.

So if we want to change the parent private variable, let’s say we want to change Fruit in Fruit.

@Test @PrepareForTest({Banana.class}) public void testChangeParentPrivate() throws Exception { Banana mBanana = new Banana(); MemberModifier. Field (Banana. Class, "fruit"). Set (mBanana, "vegetable "); Assert.assertequals (" vegetable ", mbanana.getfruit ()); assert.assertequals (" vegetable ", mbanana.getfruit ()); }Copy the code

3. The mock final method

@RunWith(PowerMockRunner.class) public class PowerMockitoFinalMethodTest { @Test @PrepareForTest({Banana.class}) public void testFinalMethod() throws Exception { Banana mBanana = PowerMockito.mock(Banana.class); PowerMockito.when(mBanana.isLike()).thenReturn(false); Assert.assertFalse(mBanana.isLike()); }}Copy the code

The method is the same as mockito, but we successfully modified the return value of the isLike method using PowerMock.

Mock constructors

@Test @PrepareForTest({Banana.class}) public void testNewClass() throws Exception { Banana mBanana = PowerMockito.mock(Banana.class); Powermockito.when (mbanana.getBananainfo ()).thenreturn (" big banana "); WhenNew (banana.class).withnoarguments ().thenreturn (mBanana); //new new object Banana newBanana = newBanana (); Assert.assertequals (" big banana ", newbanana.getBananainfo ()); assert.assertequals (" big banana ", newbanana.getBananainfo ()); }Copy the code

The whenNew method means that when the object is later new, it returns some Mock object instead of actually new the new object. If the constructor has arguments, they can be passed in the withNoArguments method.

5. Other

We mentioned above that to use PowerMock we must add @runwith (PowerMockRunner. Class), but we sometimes use multiple test frameworks and @runwith can take over. At this point we can use @rule. The code is as follows:

@Rule
public PowerMockRule rule = new PowerMockRule();Copy the code

Remember that using this method requires adding dependencies:

TestCompile "org. Powermock: powermock - module - junit 4 - rule: 1.7.3" testCompile "Org. Powermock: powermock - the classloading - xstream: 1.7.3." "Copy the code

All of this code has been uploaded to Github. We hope you can give us a lot of support!

Reference 3.

  • Powermock document

  • PowerMock handles special unit tests