用了这么久的 SoapUI,还未详细介绍过它的可编程性。以下两份文档,是我在学习 SoapUI 过程中看得最多的内容。
https://www.soapui.org/functional-testing/properties/working-with-properties.html
https://www.soapui.org/scripting-properties/tips-tricks.html
其实 SoapUI 官方的教程已经非常详尽了,通过对这些教程的举一反三,我们可以很容易实现“根据日期规则生成随机字符串”,“在请求 header 中增加签名字段”,“根据请求 header 中的 Accept-Language 字段,来决定验证中文还是英文提示”等等场景。
现在 SoapUI 已经不是我们 API 测试的主力了,我们也不再续买 licenese ,我用的是最新免费版 5.3.0。由于免费版没有商业版的 DataGen 等功能,很多操作只能靠自己写 groovy 实现了。好在我只是偶尔用用,写 groovy 工作量不大。
SoapUI 项目如下,你可以直接导入这个项目文件。
https://github.com/applewu/testlab-groovy/blob/master/SoapUI/ex01/pingpp-payment-soapui-project.xml
言归正传,请结合上述 SoapUI 项目源码,来阅读下面的内容。
生成随机字符串,作为 property 保存
import org.apache.commons.lang.RandomStringUtils;
String order_no = (RandomStringUtils.random(10, true, false));
def props = testRunner.testCase.getTestStepByName( "Properties" )
props.setPropertyValue("order_no",order_no)
从 properties 中读取变量值,该值属于 request body 的一部分
上面已经实现了设置 Properties 中的 order_no 值,我们在 request body 中直接通过变量名 ${Properties#order_no} 使用。例如:
{"body": "test1body1", "client_ip": "127.0.0.1", "uid": "pingxxx_sales03", "app": "${Properties#app1_id}", "description": "test1-description", "merchant_order_no": "${Properties#order_no}", "currency": "cny", "amount": 200,"subject": "${Properties#subject}"}
根据规则用私钥生成签名,添加到 request header 字段中
在这一个环节,我们要解决:1. 私钥文件读取;2. 具体的签名逻辑。
首先,这里我们是将私钥文件与项目文件保存在同一目录下,因而我们要获得 SoapUI 项目的当前路径;
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
String projectDir = groovyUtils.projectPath
def privateKeyPath = "${projectDir}/privatekey.key"
其次,这里的签名逻辑是采用 RSA 私钥对 "请求 body + url + 时间戳"生成签名。由于 Get 请求时,请求 body 要设置为空,因而我们还要获取当前请求 method,以便进行判断。
def method = tr.getRestMethod().getMethod().toString()
def request = context.expand('${request#Request}')
FileInputStream inputStream = new FileInputStream(privateKeyPath);
byte[] keyBytes = new byte[inputStream.available()];
inputStream.read(keyBytes);
inputStream.close();
String PEMEncodedPrivateKey = new String(keyBytes, charset);
String timeStamp = System.currentTimeMillis()/1000L + "";
String data
// 去掉时间戳的秒
if(method == "GET"){
data = url + timeStamp[0..9]
}else if(request.length().toInteger()>0)
{
data = request + url + timeStamp[0..9]
}
data 已经有了,加密动作就不详述了。如果你测试的接口项目提供了 Java SDK,那简直就是一项翻译工作,把 SDK 里面的 java 生成签名代码翻译为 grovvy 语法就可以了。
总结
了解了 groovy 的用法之后,我们就可以用 SoapUI 实现更复杂的测试逻辑。可惜 SoapUI 实在太吃内存了,用着总是卡死,不然我应该会更喜欢用它 :)