欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

PowerMockito的基本使用解析

程序员文章站 2023-01-16 12:56:51
powermockito经常会结合mockito使用,先说一下这2个的介绍:1.mockito和powermockito的简介mockito和powermockito是什么东西呢?他们有什么作用呢?m...

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的基本使用解析

PowerMockito的基本使用解析

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设置顺序的。一定要注意。

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