Why write unit tests

  • Advantages: Unit tests reduce bug rates and improve code quality. You can also familiarize yourself with the business through unit tests.
  • Company requirements: Some companies may also mandate the percentage of single test coverage required for each code addition or change to be eligible for a code merge request.

Choose which unit test framework

At present, junit4+Mock (Mockito, JMock, EasyMock, PowerMock) is a common Java unit test tool. Why was PowerMock chosen? When doing unit testing, we find that the method we are testing has many external dependencies or calls to other services (sending mail, network communication, SOA calls). And we have no control over these externally dependent objects. To solve this problem, we need to use mocks to simulate these externally dependent objects and thus control them. We only care if our own business logic is correct. This is where PowerMock comes in. It can mock not only external dependencies, but also private methods, final methods, and so on.

What is a powerMocker

PowerMock is a framework that extends other mock libraries, such as EasyMock, with more powerful capabilities. PowerMock uses custom class loaders and bytecode operations to simulate static methods, constructors, final classes and methods, private methods, remove static initializers, and more. By using a custom classloader, you do not need to make any changes to the IDE or continuous integration server, thus simplifying the adoption process. Developers familiar with the supported simulation frameworks will find PowerMock easy to use because the entire expected API is the same, both for static methods and constructors. PowerMock is designed to extend an existing API with a small number of methods and annotations to enable additional functionality.

Commonly used annotations

  • @runWith (PowerMockRunner.class) tells JUnit to use PowerMockRunner to test
  • PrepareForTest({demodao.class}) All classes to be tested are listed here. This applies to classes that simulate final or have final, private, static, or native methods
  • @PowerMockIgnore({“javax.management.“, “javax.net.ssl.“}) to resolve a ClassLoader error after using powerMock
  • @ SuppressStaticInitializationFor don’t let the static load code Other more annotations can refer to: github.com/powermock/p…

How to start

JUnit 4.4 or later
<properties>
    <powermock.version>2.0.2</powermock.version>
</properties>
<dependencies>
   <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-module-junit4</artifactId>
      <version>${powermock.version}</version>
      <scope>test</scope>
   </dependency>
   <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-api-mockito2</artifactId>
      <version>${powermock.version}</version>
      <scope>test</scope>
   </dependency>
</dependencies>
Copy the code

PowerMock sample

This is a class that needs to be mocked and it has private methods, static methods, and so on and so forth and I’ll show you how to mock each method.

/ * * * *@Date: 2020/3/31
 * @Description: * /
@Repository
public class DemoDao {
    public String mockPublicMethod(String type) throws Throwable {
        throw  new Throwable();
    }
    public final String mockFinalMethod(String type) throws Throwable {
        throw  new Throwable();
    }
    public static String mockStaticMethod(String type) throws Throwable {
        throw  newThrowable(); }}/ * * *@Date: 2020/3/31 name *@Description: * /
@Component
public class DemoService extends AbstractDemo{

    @Autowired
    private DemoDao demoDao;

    public String mockPublicMethod(a) throws Throwable {
        return demoDao.mockPublicMethod("demo");
    }

    public String mockFinalMethod(a) throws Throwable {
        return demoDao.mockFinalMethod("demo");
    }

    public String mockStaticMethod(a) throws Throwable {
        return DemoDao.mockStaticMethod("demo");
    }


    private String callPrivateMethod(String type) {
        return type;
    }

    public String mockPublicMethodCallPrivateMethod(String type) throws Throwable {
        return callPrivateMethodThrowable(type);
    }

    private String callPrivateMethodThrowable(String type) throws Throwable {
        throw new Throwable();
    }

    public String mockExtendMethod(String type) throws Throwable {
       return getExtendMethod();
    }

    public static String UUID = "uuid";
}

Copy the code
Mock common public methods
   / * * *@Date: 2020/4/24 all *@Description: * /
   @RunWith(PowerMockRunner.class)
   public class DemoServiceTest {
   
       @InjectMocks
       private DemoService demoService;
       @Mock
       private DemoDao demoDao;
       
    /** * mock normal method *@throws Throwable
    */
       @Test
       public void mockPublicMethod(a) throws Throwable {
           String type = UUID.randomUUID().toString();
           PowerMockito.when(demoDao.mockPublicMethod(any())).thenReturn(type);
           String result = demoService.mockPublicMethod();
           Assert.assertEquals(type, result);
       }
Copy the code
The mock Final method

It’s the same as a normal method, except that it requires a PrepareForTest annotation on the class

    @RunWith(PowerMockRunner.class)
    @PrepareForTest(DemoDao.class)
    public class DemoServiceTest {
    
        @InjectMocks
        private DemoService demoService;
        @Mock
        private DemoDao demoDao;
    
       
      /** * Mock Final@throws Throwable
          */
         @Test
         public void mockFinalMethod(a) throws Throwable {
             String type = UUID.randomUUID().toString();
             PowerMockito.when(demoDao.mockFinalMethod(any())).thenReturn(type);
             String result = demoService.mockFinalMethod();
             Assert.assertEquals(type, result);
         }
  
Copy the code
Mock static methods (using PowerMockito.mockStatic) are also decorated with the PrepareForTest annotation for the mock class.
  @RunWith(PowerMockRunner.class)
  @PrepareForTest(DemoDao.class)
  public class DemoServiceTest {
  
      @InjectMocks
      private DemoService demoService;
      @Mock
      private DemoDao demoDao;
      /** * Mock static method *@throws Throwable
       */
      @Test
      public void mockStaticMethod(a) throws Throwable {
          String type = UUID.randomUUID().toString();
          PowerMockito.mockStatic(DemoDao.class);
          PowerMockito.when(DemoDao.mockStaticMethod(any())).thenReturn(type);
          String result = demoService.mockStaticMethod();
          Assert.assertEquals(type, result);
      }
Copy the code
Calling private methods
    /** * Call private method **@throws Throwable
     */
     /** * Call private method **@throws Throwable
        */
       @Test
       public void callPrivateMethod(a) throws Throwable {
           // The first way
           String type = UUID.randomUUID().toString();
           Method method = PowerMockito.method(DemoService.class, "callPrivateMethod", String.class);
           String result = (String) method.invoke(demoService, type);
           Assert.assertEquals(type, result);
   
           // The second way
           String result1 = Whitebox.invokeMethod(demoService, "callPrivateMethod", type);
           Assert.assertEquals(type, result1);
       }
Copy the code
Mock private methods (The mock class is also decorated with PrepareForTest annotations.)
    /** * Mock private methods@throws Throwable
     */
    @Test
    public void mockPrivateMethod(a) throws Throwable {
        String type = UUID.randomUUID().toString();
        // This sentence is important
        demoService = PowerMockito.spy(demoService);
        PowerMockito.doReturn(type).when(demoService,"callPrivateMethodThrowable",type);
        String result = demoService.mockPublicMethodCallPrivateMethod(type);
        Assert.assertEquals(type, result);
    }
Copy the code
Mock superclass method
     /** * Mock superclass method **@throws Throwable
       */
      @Test
      public void mockExtendMethod(a) throws Throwable {
          String type = UUID.randomUUID().toString();
          // Requires the methods of the mock superclass
          Method method = PowerMockito.method(AbstractDemo.class, "getExtendMethod");
          // InvocationHandler
          PowerMockito.replace(method).with((proxy, method1, args) -> type);
          String result = demoService.mockExtendMethod(type);
          Assert.assertEquals(type, result);
      }
Copy the code
Mock constructors
     public DemoService(a) {
            throw new NullPointerException();
        }
    @Test
    public void mockConstructorMethod(a) throws Throwable {
        PowerMockito.whenNew(DemoService.class).withNoArguments().thenReturn(demoService);
    }
Copy the code
The mock field
        /** * Mock field */
        @Test
        public void mockFiled(a){
            String uuid = UUID.randomUUID().toString();
            Whitebox.setInternalState(DemoService.class, "UUID",uuid);
            Assert.assertEquals(DemoService.UUID, uuid);
        }
Copy the code

The end of the

  • Due to their lack of knowledge, it is hard to avoid mistakes, if you find the wrong place, also hope to leave a message to me to point out, I will correct it.
  • If you think the article is good, your retweet, share, praise, like, comment is the biggest encouragement to me.
  • Thank you for reading. I very much welcome and thank you for your attention.