HttpRunner 使用 Python 的 JPype 模块调用 Jar 包

wuhao for 郑州软件测试圈 · 2018年03月19日 · 最后由 dameng58 回复于 2018年06月28日 · 6125 次阅读
本帖已被设为精华帖!

背景与需求

  1. 最近学习并安装使用了HttpRunner框架去尝试做接口测试,并有后续在公司推广的打算。
  2. HttpRunner由Python开发,调用接口时需要依赖Python;而大多数公司的扩展工具包使用Java编写,测试同学使用Python重新实现不显示。
  3. 目前网上的资料均停留在对单个JAR包的引用于使用上,对于使用多个有依赖关系的JAR包的方法并未提及。

JPype介绍

1. JPype是什么:

JPype是一个能够让 python 代码方便地调用 Java 代码的工具,从而克服了 python 在某些领域(如服务器端编程)中的不足。
JPype的实际运行环境仍然是python runtime,只是在运行期间启动了一个嵌入的jvm。

2. 环境搭建

我的开发环境是: Windows7_64bit + Python3.5_64bit + JDK1.8_64bit + +Jpype_0.5.52 (Python和JDK的位数一定要相同)

  1. 安装JPype: pip3.5 install JPype1-py3
  2. 找到JRE中的 jvm.dll文件 (在JDK中的路径类似如下路径: F:/Java/jdk1.8.0_45/jre/bin/server/jvm.dll)

3. JPype使用说明

1. 启动JVM

JPype 提供的 startJVM() 函数的作用是启动 JAVA 虚拟机,所以在后续的任何 JAVA 代码被调用前,必须先调用此方法启动 JAVA 虚拟机。
jpype.startJVM() 的定义:
startJVM(jvm, *args)

3. 引用第三方JAVA扩展包

很多时候,在 python 项目中需要调用第三方的 Java 扩展包,这也是 JPype 的一个重要用途。
通过在 JVM 启动参数增加:-Djava.class.path = ext_classpath,实现在 Python 代码中调用已有的 Java 扩展包。
通过在 JVM 启动参数增加: -Djava.ext.dirs = ext_dirs , 实现在Python 代码中引入 Java 扩展包的其他依赖包。

注意事项
当有其他依赖JAR包时,一定要使用-Djava.ext.dirs = ext_dirs进行引入,否则在调用类对象时会报错:
jpype._jexception.ExceptionPyRaisable: java.lang.Exception: Class not found

2. 关闭JVM

当使用完 JVM 后,可以通过 jpype.shutdownJVM() 来关闭 JVM,该函数没有输入参数。当 python 程序退出时,JVM 会自动关闭。

4. 实践

1. 直接调用JAVA API

from jpype import *  
import os.path
startJVM("F:/Java/jdk1.8.0_45/jre/bin/server/jvm.dll", "-ea")
java.lang.System.out.println("hello World")
shutdownJVM()

2. 调用JAVA第三方扩展包

JAR包源代码为:

package com.test;

import org.apache.log4j.Logger;

public class MathDemo {
public static Logger logger = Logger.getLogger(MathDemo.class.getName());
public int add(int a, int b) {
return a+b;
}
}

将此源码打包编译为:MathDemo.jar,而MathDemo.jar又依赖log4j-1.2.16.jar。

Python脚本代码为:

from jpype import *
import jpype

jarpath = os.path.join(os.path.abspath('.'), 'F:/JPypeTestl/MathDemo.jar')
dependency = os.path.join(os.path.abspath('.'), 'F:/JPypeTestl/dependency')
jpype.startJVM("F:/Java/jdk1.8.0_45/jre/bin/server/jvm.dll", "-ea", "-Djava.class.path=%s" %jarpath,"-Djava.ext.dirs=%s" %dependency) #当有依赖的JAR包存在时,一定要使用-Djava.ext.dirs参数进行引入
JClass = jpype.JClass('com.test.MathDemo')
instance = JClass()
result = (instance.add(10, 20)
print (result)
jpype.shutdownJVM()

5. 注意事项

在启动JVM的时候,默认不会把JDK中 “\jre\lib\ext” 扩展包下的JAR包引入,所以为了避免调用过程中出现问题,建议将 “\jre\lib\ext” 内的JAR, 均放入我们自己的 "dependency" 目录,自行导入。
我在工作中就遇到过使用JAVA调用JAR成功,但是使用JPypy调用JAR,缺乏ext扩展目录中JAR包的情况。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 20 条回复 时间 点赞

支持多次调用jar包么?
启动JVM 如果是多次的话 好像有点问题

boxuezhai 回复

Jpype本身存在一个BUG,就是无法多次启动和关闭JVM,所以可以尝试使用不关闭JVM的方法, 且在启动JVM前,加入JVM是否启动的判断语句:

if not isJVMStarted():
startJVM(jpype.getDefaultJVMPath())
java.lang.System.out.println("Sencond time, i am coming back")
seveniruby 将本帖设为了精华贴 03月19日 12:37
wuhao 回复

好的 我回去试试

仅楼主可见
wuhao 回复

红魔啊

JPype只会报一种错误,找不到class~~ 定位问题的时候挺蛋疼的

顶一个啊!

weamylady 回复

错误描述单一,定位问题的确蛋疼😂用的时候得多爬坑,所以希望大家使用过程中遇到关于jpype的问题和解决方法,也都可以回复出来

wuhao #10 · 2018年03月21日 作者
yinquanwang 回复

还没试和django结合,目前尝试和httprunner结合,包括多次调用在内,倒是还良好

wuhao #11 · 2018年03月27日 作者
liwei_721 回复

谢谢支持

wuhao #12 · 2018年03月27日 作者
diao2007 回复

老红魔了~~~

不明觉厉👍

谢谢大佬分享

使用过程中发现,两者的数据类型转换,真是一步一个坑啊😂

wangqunsong 回复

看看github文档,就少走弯路

在使用过程中会碰到JVM莫名崩溃的情况,不知道大佬碰到过没?后来还是觉得把java封装成接口调用更合适点。。

mark一下

boxuezhai 回复

可以将多个jar包全部加载在虚拟机里,可重复调用。
若想要重启jvm。可以吧启动jvm这些操作放在一个独立的线程里面完成,需要重启的时候直接杀掉重新启动

我想问下,用jpype时如果调用java类的main方法?

dameng58 回复

已解决。。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册