操作数是 TestHub 数据的最小操作单元,
我们用 FormulaNode 表示一个的操作数 - TestHub 中内置了 5 种基础操作数
- DataNode 表示固定值,是有配置人员手动指定的, 例如:
xxxx - PathNode 表示变量值,可以基于 jsonPath 从决策上下文中获取指定的变量值,标识为
${xxx.yyy} - FuncNode 表示方法型函数的调用,标识为
%{方法名(形参 1:操作数,......)} - ArithmeticNode 表示计算算数运算, 例如:
1+2+3*4/5%3 - MixNode 表示混合表达式
操作对象
后续介绍均以上下文中存在如下数据为前提
```xml copy { “store”: { “book”: [ { “category”: “reference”, “author”: “Nigel Rees”, “title”: “Sayings of the Century”, “price”: 8.95 }, { “category”: “fiction”, “author”: “Evelyn Waugh”, “title”: “Sword of Honour”, “price”: 12.99 }, { “category”: “fiction”, “author”: “Herman Melville”, “title”: “Moby Dick”, “isbn”: “0-553-21311-3”, “price”: 8.99 }, { “category”: “fiction”, “author”: “J. R. R. Tolkien”, “title”: “The Lord of the Rings”, “isbn”: “0-395-19395-8”, “price”: 22.99 } ], “bicycle”: { “color”: “red”, “price”: 19.95 } }, “expensive”: 2 }
## 语法### 固定值-DataNodedata="root"中的 我们写死的 root 其实就是 DataNode 类型的操作数```xml copy<param code="password" name = "密码" dataType="STRING" data="root"/>
| 写法 | 例子 | 值 |
|---|---|---|
-1.0086 |
数字 | -1.0086 |
{attr:{a:1},attr1:1} |
json 对象 | {“attr”:{“a”:1},”attr1”:1} |
[${expensive},1] |
列表 操作对象的 expensive 做为第一个元素,1 是第二个元素 | [2,1] |
变量值-PathNode
::: warning PathNode 几乎支持了所有 jsonPath 的语法,但是我们不支持 $['store']['book'][0]['title'] 这种[]的写法
如果目前的语法满足不了你的测试过程,请于gitee仓库提 lssues,我们会优先支持。
jsonPath 语法学习 请参考 https://github.com/alibaba/fastjson/wiki/JSONPath
:::
| 写法 | 例子 | 值 |
|---|---|---|
${expensive} |
操作对象的 expensive 的值 | 2 |
${store.book.price} |
操作对象的 store 的每一个 book 的 price 值 | [8.95, 12.99, 8.99, 22.99] |
${store.book[-1].author} |
操作对象的 store 的最后一个 book 的 author | J. R. R. Tolkien |
${store.book[0:2].author} |
操作对象的 store 的 0 到 2book 的 author | Nigel Rees,Sword of Honour,Herman Melville |
${store.book[?(isbn)]} |
操作对象的 store 的 book 中 isbn 属性不等于空的 | Herman Melville,J. R. R. Tolkien |
${store.book[author='Nigel Rees'].title} |
操作对象的 store 的 book 中 author 等于 Nigel Rees 的 book 的 title | Sayings of the Century |
内置方法-FuncNode
| 写法 | 例子 | 值 |
|---|---|---|
%{getNowTime()} |
获取当前时间 | 看表 |
%{add(attr1:1,attr2:2)} |
进行 1+2 ,key:val 的写法 | 3 |
%{add(1,2)} |
进行 1+2 默认 key 为下标的写法 | 3 |
内置函数是我们基于 SPI 机制提供的扩展点之一,目前我们实现了这些内置函数
如果有不满足你的可以按照一下方式扩展
- 继承 FunctionHandler
```java copy package org.dromara.testhub.nsrule.core.executer.mode.base.function;
import com.alibaba.fastjson.JSONObject; import org.dromara.testhub.nsrule.core.executer.context.Context;
public interface FunctionHandler { String getName();
Object execute(Context context, JSONObject data);
}
2. 在 META-INF.services 路径下的 org.dromara.testhub.nsrule.core.executer.mode.base.function.FunctionHandler 配置的你扩展方法### 算数运算-ArithmeticNode是的我们支持了手写算数运算的表达式| 符号 | 作用 || ---- | ------ || + | 加 || - | 减 || `*` | 乘 || / | 除 || % | 取余 || () | 优先级 || 写法 | 例子 | 值 || --------------- | ------------------- | --- || `1+2+3*4/5%3` | 计算`1+2+3*4/5%3` | 5.4 || `1+(2+3)*4/5%3` | 计算`1+(2+3)*4/5%3` | 2 |### 混合表达式-MixNode用户组合所有 FormulaNode 最终结果返回字符串| 写法 | 例子 | 值 || ------------------------------------------------ | ------------------------------------------- | ----------------------------------- || `http:${expensive}:10010/server/workerHeartbeat` | 将操作对象的 expensive 的值替换后返回字符串 | http:2:10010/server/workerHeartbeat |## 实践```xml copy<?xml version="1.0" encoding="UTF-8"?><rule code="RULE_0000000013" name="Formula操作数使用说明" model="flow" project="default"><actions><action code="getData" name="操作数据" type="CONST" dataType="MAP"><bound>{"store":{"book":[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}],"bicycle":{"color":"red","price":19.95}},"expensive":2}</bound></action></actions><flows><flow code="flow1"><execute code="stp1" name="获取基础操作数据" actionCode="getData"/><execute code="stp2" name="固定值-DataNode" actionCode="check"><checkItem code="check1" name="固定值数字" msg=""><expression expressionType="relation" operationCode="eq" dataType="NUMBER" cover="-1.0086" threshold="-1.0086"/></checkItem><checkItem code="check2" name="固定值字符串" msg=""><expression expressionType="relation" operationCode="eq" dataType="STRING" cover="* 0/1 * * * ?" threshold="* 0/1 * * * ?"/></checkItem><checkItem code="check3" name="固定值列表" msg=""><expression expressionType="relation" operationCode="eq" dataType="NUMBER" coverComplex="1" cover="[${stp1.expensive},1]" thresholdComplex="1" threshold="[2,1]"/></checkItem></execute><execute code="stp3" name="变量值-PathNode" actionCode="check"><checkItem code="check1" name="操作对象的 expensive 的值" msg=""><expression expressionType="relation" operationCode="eq" dataType="NUMBER" cover="${stp1.expensive}" threshold="2"/></checkItem><checkItem code="check2" name="操作对象的 store 的每一个 book 的 price 值" msg=""><expression expressionType="relation" operationCode="eq" dataType="STRING" coverComplex="1" cover="${stp1.store.book.price}" thresholdComplex="1" threshold="[8.95,12.99,8.99,22.99]"/></checkItem><checkItem code="check3" name="操作对象的 store 的最后一个 book 的 author" msg=""><expression expressionType="relation" operationCode="eq" dataType="STRING" cover="${stp1.store.book[-1].author}" threshold="J. R. R. Tolkien"/></checkItem><checkItem code="check4" name="操作对象的 store 的 0 到 2book 的 author" msg=""><expression expressionType="relation" operationCode="eq" dataType="STRING" coverComplex="1" cover="${stp1.store.book[0:2].author}" thresholdComplex="1" threshold="[Nigel Rees,Sword of Honour,Herman Melville]"/></checkItem><checkItem code="check5" name="操作对象的 store 的 book 中 isbn 属性不等于空的 的 author" msg=""><expression expressionType="relation" operationCode="eq" dataType="STRING" coverComplex="1" cover="${stp1.store.book[?(isbn)].author}" thresholdComplex="1" threshold="[Herman Melville,J. R. R. Tolkien]"/></checkItem><checkItem code="check6" name="操作对象的 store 的 book 中 author 等于 Nigel Rees 的 book 的 title" msg=""><expression expressionType="relation" operationCode="eq" dataType="STRING" cover="${stp1.store.book[author='Nigel Rees'].title}" threshold="Sayings of the Century"/></checkItem></execute><execute code="stp4" name="内置方法-FuncNode" actionCode="check"><checkItem code="check1" name="参数key:val形式" msg=""><expression expressionType="relation" operationCode="eq" dataType="NUMBER" cover="%{add(attr1:1,attr2:2)}" threshold="3"/></checkItem><checkItem code="check2" name="参数,形式" msg=""><expression expressionType="relation" operationCode="eq" dataType="NUMBER" cover="%{add(1,2)}" threshold="3"/></checkItem></execute><execute code="stp5" name="算数运算-ArithmeticNode" actionCode="check"><checkItem code="check1" name="计算1+2+3*4/5%3" msg=""><expression expressionType="relation" operationCode="eq" dataType="NUMBER" cover="1+2+3*4/5%3" threshold="5.4"/></checkItem><checkItem code="check2" name="计算1+(2+3)*4/5%3" msg=""><expression expressionType="relation" operationCode="eq" dataType="NUMBER" cover="1+(2+3)*4/5%3" threshold="2"/></checkItem></execute><execute code="stp6" name="混合表达式-MixNode" actionCode="check"><checkItem code="check1" name="store 的 book中第expensive+1个 的 author" msg=""><expression expressionType="relation" operationCode="eq" dataType="STRING" cover="${stp1.store.book[%{add(${stp1.expensive},1)}].author}" threshold="J. R. R. Tolkien"/></checkItem><checkItem code="check2" name="store 的 book中第expensive+1个 的 author" msg=""><expression expressionType="relation" operationCode="eq" dataType="STRING" cover="${stp1.expensive}.1" threshold="2.1"/></checkItem></execute></flow></flows></rule>
