PowerMockito的基本使用解析

PowerMockito经常会结合Mockito使用,先说一下这2个的介绍:

1.Mockito和PowerMockito的简介

Mockito和PowerMockito是什么东西呢?他们有什么作用呢?

Mocktio和PowerMockito都是Mock的工具类,主要是Java的类库,Mock就是伪装的意思。

他们适用于单元测试中,对于单元测试来说,我们不希望依赖于第三方的组件,比如数据库、Webservice等。在写单元测试的时候,我们如果遇到了这些需要依赖第三方的情况,我们可以使用Mock的技术,伪造出来我们自己想要的结果。

对于Java而言,mock的对象主要是Java 方法和 Java类。

下面我就介绍一下怎么使用Mockito和PowerMockito去进行Mock。

2.Mockito和PowerMockito的区别

在我看来,PowerMockito是Mockito的一种增强,他们的PowerMockito可以调用Mockito的方法,但是对于Mocktio不能Mock的对象或者方法,我们可以使用PowerMockito来实现。

比如Mockito不能用于static Method, final method, 枚举类, private method,这些我们都可以用PowerMockito来实现,当PowerMockito和mockito结合使用的时候,我们需要考虑兼容性的问题。

两者的版本需要兼容

Mockito PowerMockito
2.8.9+ 2.x
2.8.0-2.8.9 1.7.x
2.7.5 1.7.0RC4
2.4.0 1.7.0RC2
2.0.0-beta - 2.0.42-beta 1.6.5-1.7.0RC
1.10.8 - 1.10.x 1.6.2 - 2.0
1.9.5-rc1 - 1.9.5 1.5.0 - 1.5.6
1.9.0-rc1 & 1.9.0 1.4.10 - 1.4.12
1.8.5 1.3.9 - 1.4.9
1.8.4 1.3.7 & 1.3.8
1.8.3 1.3.6
1.8.1 & 1.8.2 1.3.5
1.8 1.3
1.7 1.2.5

Ref:https://github.com/powermock/powermock/wiki/Mockito

3.具体用法

本文实现实现需要构造的接口和需要返回值的接口

引入依赖

<dependencies>
	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context-support</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-test</artifactId>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.12</version>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.mockito</groupId>
		<artifactId>mockito-all</artifactId>
		<version>2.0.2-beta</version>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.powermock</groupId>
		<artifactId>powermock-module-junit4</artifactId>
		<version>1.7.4</version>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.powermock</groupId>
		<artifactId>powermock-api-mockito</artifactId>
		<version>1.7.4</version>
		<scope>test</scope>
	</dependency>
</dependencies>

需要Mock的类:

ProcessDB.java

package com.github.mock.simple.vo;
public class ProcessDB {
    public ProcessDB(String ss){
        System.out.println(ss + " Enter ProcessDB ...");
    }

    public ProcessDB(){
        System.out.println("Enter ProcessDB ...");
    }

    public void getResultOfConnectDBNoReturn(String ss) {
        System.out.println(ss + " Enter getResultOfConnectDBNoReturn ...");
    }

    public String getResultOfConnectDB() {
        return "haha, Really went to the database";
    }
}
 

需要测试的类:

IUserService.java

package com.github.mock.simple.user;
public interface IUserService {
    public String testedMehtod();
}

UserServiceImpl.java

package com.github.mock.simple.user.impl;
import org.springframework.stereotype.Service;
import com.github.mock.simple.user.IUserService;
import com.github.mock.simple.vo.ProcessDB;

@Service
public class UserServiceImpl implements IUserService {

    @Override
    public String testedMehtod(){
        System.out.println("Enter UserServiceImpl testedMehtod ...");
        ProcessDB processDB = new ProcessDB("BB");
        processDB.getResultOfConnectDBNoReturn("AA");
        return processDB.getResultOfConnectDB();
    }
}

BussinessService.java

package com.github.mock.simple.user.impl;
import com.github.mock.simple.vo.ProcessDB;
public class BussinessService {
    public String testedMehtod() {
        System.out.println("Enter BussinessService testedMehtod ...");
        ProcessDB processDB = new ProcessDB("BB");
        processDB.getResultOfConnectDBNoReturn("AA");
        return processDB.getResultOfConnectDB();
    }
}

测试类:

MockSpringSimpleTest.java

package com.github.mock.simple.test;
import java.text.MessageFormat;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.github.mock.simple.user.IUserService;
import com.github.mock.simple.user.impl.BussinessService;
import com.github.mock.simple.user.impl.UserServiceImpl;
import com.github.mock.simple.vo.ProcessDB;

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)//Spring上下文
@PrepareForTest({BussinessService.class,UserServiceImpl.class})
@ContextConfiguration(locations = {"classpath:applicationContext-mock-inject.xml"})
public class MockSpringSimpleTest {

    //使用Spring上下文
    @Autowired
    IUserService userService;

    @Mock
    ProcessDB processDB;

    //不使用Spring上下文时,使用该注解
    @InjectMocks
    private BussinessService bussinessService;

    @Before
    public void initMocks() throws Exception {
        MockitoAnnotations.initMocks(this);
        //ReflectionTestUtils.setField(userService, "processDB", processDB);
        PowerMockito.whenNew(ProcessDB.class).withArguments("BB").thenReturn(processDB);
        // PowerMockito.whenNew(ProcessDB.class).withNoArguments().thenReturn(processDB);
    }

    @Test
    public void mockConnectDB() {
        String aa = "haha, everything is fake";
        PowerMockito.when(processDB.getResultOfConnectDB()).thenReturn(aa);
        PowerMockito.doNothing().when(processDB).getResultOfConnectDBNoReturn("AA");
        System.out.println(bussinessService.testedMehtod());
        Assert.assertEquals("haha, everything is fake", bussinessService.testedMehtod());
    }

    @Test
    public void mockConnectDB2() {
        try {
            String aa = "haha, everything is fake";
            PowerMockito.when(processDB.getResultOfConnectDB()).thenReturn(aa);
            PowerMockito.doNothing().when(processDB).getResultOfConnectDBNoReturn("AA");
            System.out.println(userService.testedMehtod());
            Assert.assertEquals("haha, everything is fake", userService.testedMehtod());
        } catch (Exception ex) {
            System.out.println("--- getMessage ---");
            System.out.println(ex.getMessage());
            System.out.println();

            System.out.println("--- toString ---");
            System.out.println(ex.toString());
            System.out.println();

//            System.out.println("--- printStackTrace ---");
//            StringWriter stringWriter = new StringWriter();
//            PrintWriter printWriter = new PrintWriter(stringWriter);
//            ex.printStackTrace(printWriter);
//            System.out.println(stringWriter.toString());
//            System.out.println();

            System.out.println("--- printStackTrace DIY ---");
            System.out.println(ex.getClass().getName() + ": " + ex.getMessage());
            StringBuilder sbException = new StringBuilder();
            for (StackTraceElement ele : ex.getStackTrace()) {
                sbException.append(MessageFormat.format("\tat {0}.{1}({2}:{3})\n",
                    ele.getClassName(), ele.getMethodName(), ele.getFileName(), ele.getLineNumber()));;
            }
            System.out.println(sbException);
            sbException = null;
//            stringWriter = null;
//            printWriter = null;
        }
    }
}

扫描注入xml

最后applicationContext-mock-inject.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
 http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.github.mock.simple"/>
</beans>

对于没有实现类,但又被依赖的接口,在applicationContext-mock-inject.xml添加如下内容 (本文不需要):

<bean name="iXxService" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="com.github.mock.simple.api.IXxService"/>
</bean>

同时在测试类里面添加下面的代码:

@Mock
iXxService iXxService;

在 @Before里面添加下面的代码

ReflectionTestUtils.setField(userService, "iXxService", iXxService);

测试结果

PowerMockito的使用技巧

当IT中有些依赖组件无法正常集成,需要mock支持测试,可以使用power mockito。

特别注意:

当对一个对象进行powermockito,应该在prepare方法,统一mock这个对象。然后在其他方法,分别进行调用when,否则,多个方法内进行mock,会出错。

比如有个 Service处于IT case的底层,普通的mock根本mock不进去,但我们又不能为了集成测试,为这个testcase单独开一个口子,注入mock对象。power mockito强大的mock能力在这里可以用上。

比如:

我的mock对象impalaService它在schmaMessagehandler类里new出来的,则需要加上注解。

首先在test 类的开头,加上注解头部,头部类是mock对象所在类。

@RunWith(PowerMockRunner.class)
@PrepareForTest({HttpClient.class,SchemaMessageHandler.class})

其次:

PooledImpalaService impalaService = PowerMockito.mock(PooledImpalaService.class);
PowerMockito.whenNew(PooledImpalaService.class).withArguments((ConfigurationanyObject()).thenReturn(impalaService);
doNothing().when(impalaService).createTable(anyString(),(Schema) anyObject());

使用powermockito,注意在用any()参数时候,比如

doNothing().when(impalaService).createTable(anyString(),(Schema) anyObject());

参数列表中,只要一个使用了any(),any****,则所有参数都要用any相关的参数,否则mock不成功。

总的来说,在it当中,只有你想mock一个对象,一定可以,比如你在A类中用到了B类,那么在prepareForTest中增加A类的注解。

如下:

@PrepareForTest({A.class})然后,在it中 声明一个B类,B b = PowerMockito.mock(B.class);这时候,就可以指定b的方法的返回值,或 PowerMockit.doNothing().when(b).方法名(),让该方法什么也不做。

最后,再讲A实例化。PowerMockit是讲究mock设置顺序的。一定要注意。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

赞 (0)

相关推荐

  • 详解Java 中的UnitTest 和 PowerMock

    学习一门计算机语言,我觉得除了学习它的语法外,最重要的就是要学习怎么在这个语言环境下进行单元测试,因为单元测试能帮你提早发现错误:同时给你的程序加一道防护网,防止你的修改破坏了原有的功能:单元测试还能指引你写出更好的代码,毕竟不能被测试的代码一定不是好代码:除此之外,它还能增加你的自信,能勇敢的说出「我的程序没有bug」. 每个语言都有其常用的单元测试框架,本文主要介绍在 Java 中,我们如何使用 PowerMock,来解决我们在写单元测试时遇到的问题,从 Mock 这个词可以看出,这类问题主

  • spring中使用Mockito解决Bean依赖树问题方法

    前提 本文不是针对Mockito的入门教学 ,主要叙述如何简单的使用Mockito解决Bean依赖树问题,对于Mockito的学习请找其他的文章或者查阅官方文档 基本概念 Junit初始化及存在的问题 spring应用在unit test时,test是独立运行的,所以需要自行 init ApplicationContext,启动 Ioc容器. Junit要求:Test类中涉及的所有Spring bean 注入成功才能完成applicationContext初始化,并启动IOC容器,否则无法执行u

  • Java单元测试Mockito的使用详解

    Mockito简介 调用mock对象的方法时,不会执行真实的方法,而是返回类型的默认值,如object返回null, int返回0等,否则通过指定when(方法).thenReturn(value)来指定方法的返回值.同时mock对象可以进行跟踪,使用verify方法看是否已经被调用过.而spy对象,默认会执行真实方法,返回值可以通过when.thenReturn进行覆盖.可见mock只要避开了执行一些方法,直接返回指定的值,方便做其他测试. Service测试用例 需要的依赖 <depende

  • Spring Boot单元测试中使用mockito框架mock掉整个RedisTemplate的示例

    概述 当我们使用单元测试来验证应用程序代码时,如果代码中需要访问Redis,那么为了保证单元测试不依赖Redis,需要将整个Redis mock掉.在Spring Boot中结合mockito很容易做到这一点,如下代码: import org.mockito.Mockito; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration

  • SpringBoot项目中使用Mockito的示例代码

    Spring Boot可以和大部分流行的测试框架协同工作:通过Spring JUnit创建单元测试:生成测试数据初始化数据库用于测试:Spring Boot可以跟BDD(Behavier Driven Development)工具.Cucumber和Spock协同工作,对应用程序进行测试. 进行软件开发的时候,我们会写很多代码,不过,再过六个月(甚至一年以上)你知道自己的代码怎么运作么?通过测试(单元测试.集成测试.接口测试)可以保证系统的可维护性,当我们修改了某些代码时,通过回归测试可以检查是

  • PowerMockito的基本使用解析

    PowerMockito经常会结合Mockito使用,先说一下这2个的介绍: 1.Mockito和PowerMockito的简介 Mockito和PowerMockito是什么东西呢?他们有什么作用呢? Mocktio和PowerMockito都是Mock的工具类,主要是Java的类库,Mock就是伪装的意思. 他们适用于单元测试中,对于单元测试来说,我们不希望依赖于第三方的组件,比如数据库.Webservice等.在写单元测试的时候,我们如果遇到了这些需要依赖第三方的情况,我们可以使用Mock

  • iOS动画解析之支付宝支付打钩动画的实现方法

    前言 我们平时在用支付宝付款时,会有一个支付中的动画和一个支付完成的动画.这篇博客主要分析一下这种动画效果,效果如下: 支付宝支付动画 一.动画解析 为了方便观察,放慢了动画的速度并添加辅助线: 放慢后的动画 从图中可以看出:加载圆弧运动轨迹可分为前半段和后半段:并且圆弧的起始角度(StartAngle)和结束角度(EndAngle)在做有规律的变化: 前半段: 从-0.5π到π,这一段运动中速度较快:StartAngle不变,始终未-0.5π:EndAngle在匀速上升,一直到π:前半段中圆弧

  • Mysql中复制详细解析

    1.mysql复制概念 指将主数据库的DDL和DML操作通过二进制日志传到复制服务器上,然后在复制服务器上将这些日志文件重新执行,从而使复制服务器和主服务器的数据保持同步.复制过程中一个服务器充当主服务器(master),而一个或多个其它服务器充当从服务器(slaves).主服务器将更新重新写入二进制日志文件,并维护文件的一个索引以跟踪日志循环.这些日志可以记录发送到从服务器的更新.当一个从服务器连接主服务器时,它通知主服务器.从服务器在日志中读取的最后一次成功更新的位置.从服务器接受从那时起发

  • Redis的主从同步解析

    一.Redis主从同步原理 1.1 Redis主从同步的过程 配置好slave服务器连接的master后,slave会建立和master的连接,然后发送sync命令.无论是第一次同步建立的连接还是连接断开后的重新连接,master都会启动一个后台进程,将数据库快照保存到文件中.同时master主进程会开始收集新的写命令并缓存起来.当后台进程完成写文件后,master就将快照文件发送给slave,slave将文件保存到磁盘上,然后加载到内存将数据库快照恢复到slave上.slave完成快照文件的恢

  • 远程数据库的表超过20个索引的影响详细解析

    昨天同事参加了一个研讨会,有提到一个案例.一个通过dblink查询远端数据库,原来查询很快,但是远端数据库增加了一个索引之后,查询一下子变慢了. 经过分析,发现那个通过dblink的查询语句,查询远端数据库的时候,是走索引的,但是远端数据库添加索引之后,如果索引的个数超过20个,就会忽略第一个建立的索引,如果查询语句恰好用到了第一个建立的索引,被忽略之后,只能走Full Table Scan了. 听了这个案例,我查了一下,在oracle官方文档中,关于Managing a Distributed

  • jq源码解析之绑在$,jQuery上面的方法(实例讲解)

    1.当我们用$符号直接调用的方法.在jQuery内部是如何封装的呢?有没有好奇心? // jQuery.extend 的方法 是绑定在 $ 上面的. jQuery.extend( { //expando 用于决定当前页面的唯一性. /\D/ 非数字.其实就是去掉小数点. expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), // Assume jQuery is ready wit

  • Ajax中解析Json的两种方法对比分析

    eval();  //此方法不推荐 JSON.parse();  //推荐方法 一.两种方法的区别 我们先初始化一个json格式的对象: var jsonDate = '{ "name":"周星驰","age":23 }' var jsonObj = eval( '(' + jsonDate + ')' ); // eval();方法 var jsonObj = JSON.parse( jsonDate ); // JSON.parse(); 方

  • Jquery+asp.net后台数据传到前台js进行解析的方法

    所以在解析后台数据的时候,我们需要根据后台的数据情况,特殊处理和对待. 我这里后台用的是asp.net提供的wcf服务,也有ashx一般处理程序.大致原理差不多. C#中我们经常用的对象,有实体对象比如:User:有List集合,一般为返回列表. 复杂点的还有对象嵌套对象或者list集合的.不过没什么差别,只要看你的数据多少来决定是由js处理数据, 还是后台处理了直接返回最终结果. 1.实体对象:返回是对象的话,在js中,直接就是和你后台代码类中的对象数据是一样的. 比如下面代码,就是获取到一个

  • js解析与序列化json数据(三)json的解析探讨

    这一节我们主要讨论json的解析. JSON.parse()方法也可以接收另一个参数,该参数是一个函数,将早每个键值对上调用.为了区别JSON.stringify()接收的替换(过滤)函数(replacer),这个函数被称作还原函数(reviver),但实际上这两个函数的签名是相同的--它们都接收连个参数,一个键和一个值,而且都需要返回一个值. 如果还原函数返回undefined,则表示要从结果中删除相应的键:如果返回其他值,则将该值插入到结果中.如: 复制代码 代码如下: <html> &l

  • js解析与序列化json数据(一)json.stringify()的基本用法

    早期的JSON解析器基本上就是使用JavaScript的eval()函数.由于JSON是JavaScript语法的自己,因此eval()函数可以解析.解释并返回JavaScript的对象和数组. ECMAScript 5对解析JSON的行为进行了规范,定义了全局对象JSON. JSON对象有两个方法:stringify()和parse().在最简单的情况下,这两个方法分别用于把JavaScript对象序列化为JSON字符串和把JSON字符串解析为原生JavaScript.例如: 新建一个HTML

随机推荐