When doing unit test, may use Mockito to test, but Mockito also have insufficient, cannot mock static, final, private method and so on. And Powermock can make up for Mockito's deficiency perfectly.
Powermock uses a custom class loader and bytecode manipulation to simulate static methods, constructors, final classes and methods, private methods, removal of static initializers, and so on. By using a custom classloader, simplifying the adoption of the IDE or continuous integration Server does not require any change. Currently Powermock supports Easymock and Mockito.
In addition to powermock this tool, there are jmockit, this tool is more powerful than Powermock, the comparison results can be see https://blog.csdn.net/yasi_xi/article/details/ 24642517, about the Jmockit introduction can be: https://blog.csdn.net/zero__007/article/details/49280827.
Required JAR Packages:
Testcompile group: ' Org.powermock ', Name: ' POWERMOCK-MODULE-JUNIT4 ', version: ' 1.7.4 '
testcompile Group: ' Org.powermock ', Name: ' Powermock-api-mockito2 ', version: ' 1.7.4 '
The Powermock has two important annotations:
@RunWith (Powermockrunner.class)
@PrepareForTest ({yourclass.class})
When you need to use Powermock powerful features (mock static, final, private method, etc.), you need to annotate @preparefortest.
@InjectMocks: Creates an instance where a mock created with the @mock or @spy annotation is injected into the instance.
@Mock: Create a Mock that all the methods of the object are empty, that is, not the actual method.
@Spy: Create a mock object, @Spy decorated object must be manually new, but all methods of the object are real methods, and the return value is the same as the real method.
Notice the difference between the @mock and @spy objects in the method mock:
For a class generated by @spy, when you use when to set the analog return value, the method inside it executes first, for example:
Powermockito.when (Demo.say (argumentmatchers.anystring ())). Thenreturn ("zero");
In this way, the Demo.say () method is called first, and needs to be as follows:
---error
//Powermockito.doreturn ("zero"). When (demo). SYS (argumentmatchers.anystring ());
Powermockito.doreturn ("Zero"). When (Demo.sys (argumentmatchers.anystring ()));
---error
//Mockito.doreturn ("zero"). When (Demo.sys (argumentmatchers.anystring ()));
Correct
Mockito.doreturn ("zero"). When (demo). SYS (argumentmatchers.anystring ());
Using Powermockito.doreturn will be an error, not clear why. There is no problem with Mockito.doreturn.
The following is the code being tested:
public class Demo {
@Autowired
private userservice userservice;
public void Dealuser () {
String name = Userservice.getusername (1);
System.out.println ("Userservice.getusername ():" + name);
Userservice.handle (name);
Say (name);
}
private void Say (String name) {
System.out.println ("Say ():" + name);
SYS (name);
}
public void work () {
System.out.println ("Work () ....");
}
Public String getString () {
return utils.getobject (this, "/zero");
}
public string sys (string name) {
System.out.println ("sys ():" + name);
return name;
}
}
public class UserService {public
String getusername (int id) {
return "Hello";
}
public void handle (String s) {
System.out.println ("Handle (): ..." + s);}
}
public class Utils {
private static String url_string = "http://www.baidu.com.cn";
private static void Deal () {
System.out.println ("Deal ()" + url_string);
}
public static string GetObject (Demo object, String str) {
deal ();
System.out.println ("GetObject ()");
return url_string + str;
}
}
Test code:
Import Org.junit.Test;
Import Org.junit.runner.RunWith;
Import org.mockito.*;
Import Org.powermock.api.mockito.PowerMockito;
Import Org.powermock.core.classloader.annotations.PowerMockIgnore;
Import Org.powermock.core.classloader.annotations.PrepareForTest;
Import Org.powermock.modules.junit4.PowerMockRunner;
Import Org.powermock.reflect.Whitebox; @RunWith (Powermockrunner.class) @PrepareForTest ({demo.class, utils.class}) @PowerMockIgnore ("javax.management.*") In order to resolve the use of Powermock, prompt ClassLoader error public class Demotest {@Spy//need to manually new @InjectMocks private demo demo = NE
W Demo ();
@Mock//Non-@spy modified objects can be instantiated by the Mockito framework without manual new, private UserService userservice; /** * Test * @see demo#dealuser () */@Test public void Testdealuser () throws Exception {//C
Orrect Powermockito.when (Userservice.getusername (Argumentmatchers.anyint ())). Thenreturn ("zero007"); Error//Powermockito.doreturn ("zero007"). When (Userservice.getUserName (Argumentmatchers.anyint ()));
Correct Powermockito.doreturn ("zero007"). When (UserService). GetUserName (Argumentmatchers.anyint ()); When inside parameter if method return value is void//error//Powermockito.donothing (). When (Userservice.handle (ARGUMENTMATCHERS.A
Nystring ()));
Correct powermockito.donothing (). When (UserService). Handle (Argumentmatchers.anystring ());
Correct powermockito.donothing (). When (UserService, "Handle", argumentmatchers.anystring ()); Mock Private Method, the demo must be a mock or an instance of the spy//must first record the expected behavior powermockito.donothing (). When (demo, "Say", argumentmatchers.
AnyString ());
Demo.dealuser (); }/** * @see Demo#say (String) */@Test public void Testsay () throws Exception {//throw O Rg.mockito.exceptions.misusing.UnfinishedStubbingException://Powermockito.doreturn ("zero"). When (demo). sys
(Argumentmatchers.anystring ()); Throw Org.mockiTo.exceptions.misusing.UnfinishedStubbingException://Powermockito.doreturn ("zero"). When (Demo.sys (Argument
Matchers.anystring ()));
Correct//Mockito.doreturn ("zero"). When (demo). SYS (argumentmatchers.anystring ());
Error Mockito.doreturn ("zero"). When (Demo.sys (argumentmatchers.anystring ()));
Mockito.when (Demo.sys (argumentmatchers.anystring ())). Thenreturn ("zero");
---sys (): System.out.println (Demo.sys ("007")); Whitebox.invokemethod (demo, "Say", "Hello world!");
/test Private Method}/** * @see demo#work () */@Test public void Testwork () throws Exception {} /** * @see demo#getstring () */@Test public void tetsgetstring () throws Exception {//mock static
State method Powermockito.mockstatic (Utils.class); Powermockito.when (Utils.getobject (Argumentmatchers.any (Demo.class), argumentmatchers.anystring ())).
Thencallrealmethod (); Powermockito.donothing(). When (Utils.class, "deal");
Whitebox.setinternalstate (Utils.class, "url_string", "www.123.com");
String result = Demo.getstring ();
SYSTEM.OUT.PRINTLN (result); }
}
Powermock Simple Implementation principle
1. When a test method is annotated @preparefortest callout, when the test case is run, Creates a new Org.powermock.core.classloader.MockClassLoader instance, and then loads the class to which the test case is used (except for the system Class).
2.PowerMock will modify the class file written in the annotation @preparefortest according to your mock request (the current test class will automatically add annotations) to meet the specific mock requirements. For example, to remove the final identification of the final method, add its own virtual implementation at the front of the static method, and so on.
3. If a mock is required for the final and static methods of the system class, Powermock does not directly modify the class file of the system classes, but instead modifies the class file of the calling system classes to meet the mock requirements.
Reference:
https://blog.csdn.net/xiaoxufox/article/details/78562656
https://www.jianshu.com/p/60309d71002d
Add: such as https://blog.csdn.net/zero__007/article/details/50365311 test scenario, how to use Powermock to achieve it.
@RunWith (powermockrunner.class) @PowerMockIgnore ("javax.management.*") public class
worktest {@Test public void Testtask () throws Exception {work work = Powermockito.spy (new work ());
Othervo Othervo = Powermockito.mock (Othervo.class);
Powermockito.when (Othervo.getvalue ()). Thenreturn ("zero007");
Whitebox.setinternalstate (Work, "Othervo", Othervo);
Executorservice executor = Powermockito.mock (Threadpoolexecutor.class); Powermockito.doanswer (New answer<object> () {@Override public Object Answer (invocationonmock
Invocationonmock) throws throwable {Runnable command = invocationonmock.getargument (0);
Command.run ();
return null;
}}). When (executor). Execute (Argumentmatchers.any (runnable.class));
Whitebox.setinternalstate (Work, "executor", executor);
Work.task (); }
}