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

wuhao for 郑州软件测试圈 · 2018年03月19日 · 最后由 june7 回复于 2019年07月12日 · 5028 次阅读
本帖已被设为精华帖!

背景与需求

  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 包的情况。

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

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

FelixKang 回复

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~~ 定位问题的时候挺蛋疼的

顶一个啊!

water 回复

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

wuhao #10 · 2018年03月21日 Author
尹全旺 回复

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

wuhao #11 · 2018年03月27日 Author

谢谢支持

wuhao #12 · 2018年03月27日 Author
不二家 回复

老红魔了~~~

不明觉厉👍

谢谢大佬分享

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

sheepwood 回复

看看 github 文档,就少走弯路

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

mark 一下

FelixKang 回复

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

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

58 回复

已解决。。

22楼 已删除
simple 专栏文章:[精华帖] 社区历年精华帖分类归总 中提及了此贴 12月13日 14:44
simple [精彩盘点] TesterHome 社区 2018 年 度精华帖 中提及了此贴 01月07日 12:08

大佬 第二次调用程序崩掉 的问题解决了吗 , 我这边来取经啊

依赖的包都丢在 dependency 吗,额,怎么跟 httprunner 结合啊

大哥 (PS:我 java 基础不好)要是一个 java 文件依赖其他包里的文件,这种嵌套,怎呢导 jar 包啊,是把他们都打包成一个 jar 包吗?
还有一直提示我方法名找不到 ,快爆炸了。。。。
类似这种:类一依赖下面仨类。
求解答——————————————————————————————————————————
解决了 但是 我用到了 properties ,调用不了,提示

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