First, the official website:
Http://code.google.com/p/powermock/
First, be prepared. The official website of this open-source tool basically has no text descriptions. But it can be downloaded.Source code, Which contains some sample test cases.
When your leaders tell you, ut'sCodeThe coverage rate must reach 100% !!
You will think this person is crazy.
But now with powermock, 100% becomes the goal you can reach !!!
Powermock makes it possible for tasks that we previously thought could not be completed.
Open the powermock official website and we can see the usage:
- Mocking static methods
- Mocking final methods or classes
- Mocking private methods
- Mock construction of new objects
- Partial mocking
- Replay and verify all
- Mock policies
- Test listeners
- More to come...
It can be seen that powermock is used to cope with some strange test requirements, such as the mock private method, mock static method, and mock final method.
These requirements are traditionally not required and should not be tested.
Let's take an example to see how powermock implements the weird problem that other tools cannot solve.
Objects are instantiated within the method.
Let's look at a simple class and then examine how to complete the corresponding test.
Public class sayhi {
Public String sayhi (string a, string B ){
Adder adder = new adder ();// Instantiate an adder to add two strings together.
String result = "";
Result = adder. Add (A, B );
Return result;
}
}
Public class adder {
Public String add (string a, string B ){
Return A + "" + B;
}
}
If we want to test the sayhi class, it's easy:
Public class sayhitest extends testcase {
@ Test
Public void testsayhi (){
Sayhi SH = new sayhi ();
Asserttrue (Sh. sayhi ("ABC", "def"). inclusignorecase ("ABC Def "));
}
}
By running cobertura, we can see that the test coverage of this class is 100%. (For cobertura, I have prepared to write an article in a few days.ArticleIntroduction)
Now, the difficulty is coming ~~ Slightly change the adder class and sayhi class:
Public class AdderThrows exception{
Public String add (string a, string B ){
Return A + "" + B;
}
}
Public class sayhi {
Public String sayhi (string a, string B ){
Adder adder = new adder ();
String result = "";
Try {
// Because the adder class throws an exception, try/catch must be added when using this class.
Result = adder. Add (A, B );
} Catch (exception e ){
Result = "failed ";
}
Return result;
}
}
Now let's look at cobertura. We can see that the test coverage rate of this class is 75%. In the existing ut, there is no test on exception handling. In other words, if you want to test the coverage rate to reach 100%, you must make the adder throw an exception in ut to test whether the Code has correctly handled the exception.
Now it is time for mock to appear. What we want to do is to use the mock object to replace the real adder, forcibly let the mock object throw an exception, and further test.
For example, in this test case, we want to create a mockadder object instead of adder. When mockadder. Add () is called, an exception is thrown, and the exception processing part is entered to make the running result failed.
The real problem arises:
In the method sayhi of the sayhi class, the adder = new adder () is instantiated; that is, the adder object is instantiated directly inside the method instead of inject.
As mentioned in the introduction to mockito, mock testing is required to ensure that the mock object overwrites the real object and the mock object replaces the real object to make the desired action.
In the mockito example, we assume that the source code provides the get/set method, so we can easily use the set method to pass the mock object. That is to say, the source code that is easy to be tested should be:
Public class sayhi {
Adder adder;
Public String sayhi (string a, string B ){
Adder = getadder ();
String result = "";
Try {
Result = adder. Add (A, B );
} Catch (ioexception e ){
E. printstacktrace ();
}
Return result;
}
Public adder getadder (){
Return adder;
}
Public void setadder (adder ){
This. adder =;
}
}
For the previous sayhi class, the mock object cannot be passed in. 100% became an impossible task.
At this point, one of our options is to modify the source code. In object-oriented languages, we have always stressed flexible and independent code structures. If a class is hard to be tested, it may be a symbol of poor code structure.
Obviously, the sayhi method depends on the adder class. This method is not flexible. It is easy to modify the code of this class due to peripheral changes.
However, for various reasons, we may not want to modify the source code.
Now, the topic of this article is entered ~~~~~ How can powermock make it impossible.
Import static org. JUnit. Assert .*;
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 static org. mockito. mockito .*;
// Note that powermock depends on JUnit, testng, mockito, or easymock.
// Here I am using JUnit + mockito, so I need to import these classes above.
@ Runwith (powermockrunner. Class)
@ Preparefortest ({sayhi. Class })
// The annotation is very important. Otherwise, powermock will not take effect.
Public class sayhitest {
@ Test
Public void testsayhi () throws exception {
Adder adder = mock (adder. Class );// Mock generates a simulated object to replace the real adder.
When (adder. Add (anystring (), anystring (). thenthrow (new exception ());
// The action of the stub virtual object, that is, an exception is thrown when the add method of the simulated object is called. The mockito function is used here.
Powermockito. whennew (adder. Class). withnoarguments (). thenreturn (Adder); // Here powermock starts to play a role: When the Add. Class is instantiated, the simulated object adder is forced to replace the instantiated object in the code.
Sayhi SH = new sayhi ();
Asserttrue (Sh. sayhi ("ABC", "def"). inclusignorecase ("failed "));//Here we see the expected results: The Exception Handling statement result = "failed"; is executed
}
}
The code coverage rate is 100% ~~ Yes !!
Why can powermock become impossible? We don't need to go into details. The general implementation method is as follows:
Powermock uses a custom classloader and bytecode manipulation to enable mocking of static methods, constructors, final classes and methods, private methods, removal of static initializers and more.
To put it simply, powermock is implemented by modifying the bytecode. Class file + User-Defined Class Loader (Class Loader is one of JVM components.
You can basically think that powermock modifies your source code by modifying the bytecode file, so that the mock object replaces the called object in the source code.
Cases that were hard to be tested, such as private methods, can now be tested. Please refer to the documents on the official website ~