Detailed explanation of PowerMockito usage

1. Why use the Mock tool

      When doing unit testing , we will find that the method we want to test will reference many externally dependent objects, such as: (send mail, network communication, remote service, file system, etc.). And we can't control these externally dependent objects. In order to solve this problem, we need to use the Mock tool to simulate these externally dependent objects to complete unit testing.

      2. Why use PowerMock

      Nowadays, the more popular Mock tools such as jMock  , EasyMock  , Mockito , etc. have a common disadvantage: they cannot mock static, final, private methods, etc. And PowerMock can perfectly make up for the deficiencies of the above three Mock tools.

      3. Introduction to PowerMock

      PowerMock is a more powerful framework that extends other mock frameworks such as EasyMock. PowerMock uses a custom class loader and bytecode manipulation to mock static methods, constructors, final classes and methods, private methods, remove static initializers, and more. By using a custom class loader, no changes are required to the IDE or continuous integration server to simplify adoption. Developers familiar with the mocking frameworks supported by PowerMock will find PowerMock easy to use because the entire expected API is the same for static methods and constructors. PowerMock is designed to extend the existing API with a small number of methods and annotations to achieve additional functionality. Currently PowerMock supports EasyMock and Mockito.

      4. Getting Started with PowerMock    

      PowerMock has two important annotations:

      –@RunWith(PowerMockRunner.class)

      –@PrepareForTest( { YourClassWithEgStaticMethod.class })

      If you don't use the annotation @PrepareForTest in your test case, you can leave out the annotation @RunWith(PowerMockRunner.class), and vice versa. When you need to use the powerful functions of PowerMock (Mock static, final, private methods, etc.), you need to annotate @PrepareForTest.

      5. Basic usage of PowerMock

(1) Ordinary Mock: The object passed by the Mock parameter

          Test object code:

public class FlySunDemo {  
    public boolean callArgumentInstance(File file) {  
        return file.exists();  
    }  
}  

         Test case code: 

import java.io.File;  
import org.junit.Assert;  
import org.junit.Test;  
import org.powermock.api.mockito.PowerMockito;  
  
public class FlySunMockTest {  
    @Test  
    public void testCallArgumentInstance(){  
        //mock出入参File对象  
        File file = PowerMockito.mock(File.class);  
        FlySunDemo demo = new FlySunDemo();  
        PowerMockito.when(file.exists()).thenReturn(true);  
        Assert.assertTrue(demo.callArgumentInstance(file));  
    }  
}  

Note: Ordinary mocks do not need to be annotated with @RunWith and @PrepareForTest.    (2) The object test target code
from the new inside the Mock method :

public class FlySunDemo {  
    public boolean callArgumentInstance(String path) {  
        File file = new File(path);   
        return file.exists();  
    }  
}  

Test case code:   

import java.io.File;  
import 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;  
@RunWith(PowerMockRunner.class)  
public class FlySunMockTest {  
    @Test  
    @PrepareForTest(FlySunDemo.class)  
    public void testCallArgumentInstance(){  
        File file = PowerMockito.mock(File.class);  
        try {  
            PowerMockito.whenNew(File.class).withArguments("bbb").thenReturn(file);  
            FlySunDemo demo = new FlySunDemo();  
            PowerMockito.when(file.exists()).thenReturn(true);  
            Assert.assertTrue(demo.callArgumentInstance("bbb"));  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}  

Note: When using the PowerMockito.whenNew method, you must annotate @PrepareForTest and @RunWith. The class written in the annotation @PrepareForTest is the class where the new object code that needs to be mocked is located.

     (3) final method of Mock ordinary object

  Test object code:

public class ClassDependency {  
    public final boolean isAlive() {  
        // do something  
        return false;  
    }  
}  

 

public class FlySunDemo {  
    public boolean callFinalMethod(ClassDependency refer) {  
        return refer.isAlive();  
    }  
}  

  Test case code:

import java.io.File;  
import 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;  
  
@RunWith(PowerMockRunner.class)  
public class FlySunMockTest {  
    @Test  
    @PrepareForTest(ClassDependency.class)  
    public void testCallFinalMethod() {  
        ClassDependency refer = PowerMockito.mock(ClassDependency.class);  
        PowerMockito.when(refer.isAlive()).thenReturn(true);  
        FlySunDemo demo = new FlySunDemo();  
        Assert.assertTrue(demo.callFinalMethod(refer));  
    }  
}  

 Note: When mock final methods are required, @PrepareForTest and @RunWith must be annotated. The class written in the annotation @PrepareForTest is the class where the final method is located. 

 

(4) Static methods of Mock ordinary classes

      Test object code:

public class ClassDependency {  
    public static boolean isAlive() {  
        // do something  
        return false;  
    }  
} 
public class FlySunDemo {  
    public boolean callStaticMethod() {  
        return ClassDependency.isAlive();  
    }  
} 

Test case code:

import 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;  
  
@RunWith(PowerMockRunner.class)  
public class FlySunMockTest {  
    @Test  
    @PrepareForTest(ClassDependency.class)  
    public void testCallFinalMethod() {  
        PowerMockito.mockStatic(ClassDependency.class);  
        PowerMockito.when(ClassDependency.isAlive()).thenReturn(true);  
        FlySunDemo demo = new FlySunDemo();  
        Assert.assertTrue(demo.callStaticMethod());  
    }  
}  

 Note: When you need to mock static methods, you must annotate @PrepareForTest and @RunWith. The class written in the annotation @PrepareForTest is the class where the static method is located.

      (5) Mock private method

      Test object code: 

public class FlySunDemo {  
    public boolean callPrivateMethod() {  
        return isAlive();  
    }  
  
    private boolean isAlive() {  
        return false;  
    }  
}  

Test case code:  

import 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;  
  
@RunWith(PowerMockRunner.class)  
public class FlySunMockTest {  
    @Test  
    @PrepareForTest(FlySunDemo.class)  
    public void testCallFinalMethod() throws Exception {  
        FlySunDemo demo = PowerMockito.mock(FlySunDemo.class);  
        PowerMockito.when(demo.callPrivateMethod()).thenCallRealMethod();  
        PowerMockito.when(demo, "isAlive").thenReturn(true);  
        Assert.assertTrue(demo.callPrivateMethod());  
    }  
}  

  The class written in the annotation is the class where the private method is located.

 

(6) Static and final methods of Mock system classes 

        Test object code:   

public class FlySunDemo {  
    public String callSystemStaticMethod(String str) {  
        return System.getProperty(str);  
    }  
}  

Test case code:

import 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;  
  
@RunWith(PowerMockRunner.class)  
public class FlySunMockTest {  
    @Test  
    @PrepareForTest(FlySunDemo.class)  
    public void testCallSystemStaticMethod(){  
        FlySunDemo demo = new FlySunDemo();  
        PowerMockito.mockStatic(System.class);  
        PowerMockito.when(System.getProperty("aaa")).thenReturn("bbb");  
        Assert.assertEquals("bbb", demo.callSystemStaticMethod("aaa"));  
    }  
}  

  Description: The same as the static methods and final methods of Mock ordinary objects

 6. The omnipotent PowerMock

       (1) Verify the static method:

       PowerMockito.verifyStatic();
       Static.firstStaticMethod(param);

       (2) Extended Validation:

       PowerMockito.verifyStatic(Mockito.times(2)); // called 2 times Static.thirdStaticMethod(Mockito.anyInt()); // called with any integer value

       (3) More Mock Methods

       http://code.google.com/p/powermock/wiki/MockitoUsage13

      Seven, PowerMock simple implementation principle

       • When a test method is annotated with @PrepareForTest, when the test case is run, a new instance of org.powermock.core.classloader.MockClassLoader will be created, and then the classes used by the test case (except system classes) will be loaded.

       • PowerMock will modify the class file written in the annotation @PrepareForTest according to your mock requirements (the current test class will be automatically added to the annotation) to meet the special mock requirements. For example: remove the final flag of the final method, add your own virtual implementation at the top of the static method, etc.

       • If the final method and static method of the system class are required to be mocked, PowerMock will not directly modify the class file of the system class, but modify the class file of the calling system class to meet the mock requirements.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325455995&siteId=291194637