有了它(powermock)再也不担心单元测试不达标了

简介: 有了它(powermock)再也不担心单元测试不达标了

为什么要写单元测试

  • 优点:单元测试可以减少bug率,提升代码的质量。还可以通过单元测试来熟悉业务。
  • 公司硬性要求:有些公司可能还会强制要求,每次新增代码、或者变更代码单测覆盖率要达到多少比例才能申请代码合并请求。

选择哪个单元测试框架

目前应用比较普遍的java单元测试工具 junit4+Mock(Mockito、jmock、EasyMock、powermock)。为什么会选择powermock?

 在做单元测试的时候,我们会发现我们要测试的方法会有很多外部依赖的对象或者一些其他服务的调用比如说(发送邮件,网络通讯,soa调用)。 而我们没法控制这些外部依赖的对象。 为了解决这个问题,我们需要用到Mock来模拟这些外部依赖的对象,从而控制它们。只关心我们自己的业务逻辑是否正确。而这时powermock就起作用了,它不仅可以mock外部的依赖,还可以mock私有方法、final方法,总之它的功能很强大。

什么是powerMocker

PowerMock是一个框架,它以更强大的功能扩展了其他模拟库,例如EasyMock。 PowerMock使用自定义的类加载器和字节码操作来模拟静态方法,构造函数, 最终类和方法,私有方法,删除静态初始化程序等。通过使用自定义类加载器,无需对IDE或持续集成服务器进行任何更改,从而简化了采用过程。熟悉受支持的模拟框架的开发人员会发现PowerMock易于使用,因为整个期望API都是相同的,
无论是静态方法还是构造函数。PowerMock 旨在通过少量方法和注释扩展现有的API,以启用额外的功能。

常用注解

  • @RunWith(PowerMockRunner.class)
    告诉JUnit使用PowerMockRunner进行测试
  • @PrepareForTest({DemoDao.class})
    所有需要测试的类列在此处,适用于模拟final类或有final, private, static, native方法的类

如何开始

JUnit 4.4及以上
<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>

powerMock样例

这是一个需要被mock的类里面有私有方法、静态方法、等等下面一一来演示各个方法的mock功能。

/**
 *
 * @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  new Throwable();
    }
}
/**
 * @Date: 2020/3/31 11:34
 * @Description:
 */
@Component
public class DemoService extends AbstractDemo{

    @Autowired
    private DemoDao demoDao;

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

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

    public String mockStaticMethod() 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";
}
mock普通公共方法
   /**
    * @Date: 2020/4/24 14:22
    * @Description:
    */
   @RunWith(PowerMockRunner.class)
   public class DemoServiceTest {
   
       @InjectMocks
       private DemoService demoService;
       @Mock
       private DemoDao demoDao;
       
    /**
    * mock 普通方法
    * @throws Throwable
    */
       @Test
       public void mockPublicMethod() throws Throwable {
           String type = UUID.randomUUID().toString();
           PowerMockito.when(demoDao.mockPublicMethod(any())).thenReturn(type);
           String result = demoService.mockPublicMethod();
           Assert.assertEquals(type, result);
       }
mock Final方法

跟普通方法是一样的,唯一的区别是需要在类上加入PrepareForTest注解

    @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() throws Throwable {
             String type = UUID.randomUUID().toString();
             PowerMockito.when(demoDao.mockFinalMethod(any())).thenReturn(type);
             String result = demoService.mockFinalMethod();
             Assert.assertEquals(type, result);
         }
  
mock静态方法(使用 PowerMockito.mockStatic)被mock的类也要用PrepareForTest注解修饰。
  @RunWith(PowerMockRunner.class)
  @PrepareForTest(DemoDao.class)
  public class DemoServiceTest {
  
      @InjectMocks
      private DemoService demoService;
      @Mock
      private DemoDao demoDao;
      /**
       * mock 静态方法
       * @throws Throwable
       */
      @Test
      public void mockStaticMethod() 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);
      }
调用 private方法
    /**
     * 调用私有方法
     * 
     * @throws Throwable
     */
     /**
        * 调用私有方法
        * 
        * @throws Throwable
        */
       @Test
       public void callPrivateMethod() throws Throwable {
           // 第一种方式
           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);
   
           //第二种方式
           String result1 = Whitebox.invokeMethod(demoService, "callPrivateMethod", type);
           Assert.assertEquals(type, result1);
       }

##### mock 私有方法(被mock的类也要用PrepareForTest注解修饰。)

    /**
     * mock私有方法
     *
     * @throws Throwable
     */
    @Test
    public void mockPrivateMethod() throws Throwable {
        String type = UUID.randomUUID().toString();
        // 重点这一句
        demoService = PowerMockito.spy(demoService);
        PowerMockito.doReturn(type).when(demoService,"callPrivateMethodThrowable",type);
        String result = demoService.mockPublicMethodCallPrivateMethod(type);
        Assert.assertEquals(type, result);
    }
mock父类方法
     /**
       * mock父类方法
       *
       * @throws Throwable
       */
      @Test
      public void mockExtendMethod() throws Throwable {
          String type = UUID.randomUUID().toString();
          // 需要mock的父类的方法
          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);
      }
mock构造方法
     public DemoService() {
            throw new NullPointerException();
        }
    @Test
    public void mockConstructorMethod() throws Throwable {
        PowerMockito.whenNew(DemoService.class).withNoArguments().thenReturn(demoService);
    }
mock字段
        /**
         * mock 字段
         */
        @Test
        public void mockFiled(){
            String uuid = UUID.randomUUID().toString();
            Whitebox.setInternalState(DemoService.class, "UUID",uuid);
            Assert.assertEquals(DemoService.UUID, uuid);
        }

结束

  • 由于自己才疏学浅,难免会有纰漏,假如你发现了错误的地方,还望留言给我指出来,我会对其加以修正。
  • 如果你觉得文章还不错,你的转发、分享、赞赏、点赞、留言就是对我最大的鼓励。
  • 感谢您的阅读,十分欢迎并感谢您的关注。
目录
相关文章
|
1月前
|
Java 测试技术 Maven
Java一分钟之-PowerMock:静态方法与私有方法测试
通过本文的详细介绍,您可以使用PowerMock轻松地测试Java代码中的静态方法和私有方法。PowerMock通过扩展Mockito,提供了强大的功能,帮助开发者在复杂的测试场景中保持高效和准确的单元测试。希望本文对您的Java单元测试有所帮助。
133 2
|
5月前
|
Java 测试技术 Spring
详解单元测试问题之PowerMock不建议使用如何解决
详解单元测试问题之PowerMock不建议使用如何解决
48 1
|
6月前
|
XML 设计模式 Java
PowerMock:静态方法与私有方法测试
PowerMock是Java单元测试中扩展Mockito的框架,允许模拟静态方法、构造函数、私有方法和final类,以增强测试隔离和覆盖率。主要应用场景包括静态方法模拟、私有方法测试和构造函数/Final类模拟。然而,使用时需注意配置复杂性、避免过度使用、精确控制模拟行为和遵循最佳实践。示例展示了如何模拟静态方法,通过添加PowerMock依赖和使用PowerMockito.mockStatic进行静态方法的模拟和验证。正确使用PowerMock能提升测试质量,但应谨慎以保持代码可读性和测试有效性。
382 5
PowerMock:静态方法与私有方法测试
|
6月前
|
设计模式 Java 测试技术
Java一分钟之-PowerMock:静态方法与私有方法测试
【6月更文挑战第4天】PowerMock是扩展Mockito的框架,用于模拟静态方法、构造函数和私有方法,以增强Java单元测试的隔离性和覆盖率。核心应用场景包括静态方法模拟、私有方法测试和Final类模拟。常见问题包括配置复杂、过度使用和忽略模拟的真实行为。解决方案包括遵循官方文档、谨慎使用PowerMock、精确控制模拟逻辑和遵循最佳实践。示例展示了如何模拟静态方法,通过添加PowerMock依赖和使用`PowerMockRunner`、`PrepareForTest`注解,以及`PowerMockito.mockStatic`和`verifyStatic`方法进行测试。
377 0
Java一分钟之-PowerMock:静态方法与私有方法测试
|
6月前
|
XML 设计模式 Java
PowerMock的静态方法与私有方法怎么测试?
**PowerMock**是Java单元测试中的增强工具,扩展了Mockito,支持模拟静态方法、构造函数、私有方法和final类,促进更高测试覆盖率。它用于隔离依赖,测试静态方法和私有方法。常见问题包括配置复杂性、过度使用、忽略真实行为模拟和最佳实践。解决方案包括遵循官方文档、谨慎使用、精确模拟和测试后清理。示例展示了如何模拟静态方法,通过添加PowerMock依赖和使用`@RunWith(PowerMockRunner.class)`、`@PrepareForTest`注解,以及`PowerMockito.mockStatic()`进行静态方法模拟。
142 0
|
Java 测试技术 Maven
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(1)
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(1)
320 0
|
Java 测试技术
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(2)
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(2)
260 0
|
Java 测试技术
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(3)
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(3)
220 0
|
Java 测试技术
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(4)
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(4)
912 0
|
Java 测试技术
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(5)
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(5)
178 0