[toc]
属性扩展可以用来在属性值、请求正文、脚本等位置插入可变内容(即动态内容)。本节将介绍如何自己手写属性扩展,另外,你也可以通过可视化界面 [Get Data](GetData对话框.md) 对话框来辅助生成属性扩展。
# 语法
一个典型的属性扩展语法:
```
${#Scope#Property-Name}
```
包括更多参数的完整语法:
```
${#Scope#Property-Name[::DataSource-Row][#Path-Expression]}
```
其中:
**Scope(作用域)**
属性的所属范围,如 `#Project#` ,`#TestCase#` 等等。
完整的可用作用域列表请参考 [这里](#scope-parameter-values) 。
**Property-Name(属性名称)**
期望属性的名称。
**DataSource-Row(数据源行号)**
可选。用于和数据源属性(列)有关的属性扩展。如果你的测试在每次迭代时获取的是多行数据,你可以使用这个参数来指定需要的某一行,例如:
```
${DataSouceTestStep#MyProperty::1}
```
索引从零开始。上面的示例中,获取的是某次迭代所返回数据集中的第二行。
如果要指定每次迭代返回的行数,在测试步骤 [DataSource](DataSource.md) 的设置中修改 **Row Per Iteration** 选项的值。请注意,**DataSource-Row** 的最大值应该小于测试步骤 DataSource 设置中 **Row Per Iteration** 选项的值。
更多用法请参考示例:[获取指定行的属性值](DataSource.md) 。
**Path-Expression(路径表达式)**
可选。用于提取 XML 或 JSON 数据。为了从 XML 或 JSON 内容中获取指定的值,需要给出对应的 XPath 或 JSONPath 表达式。
>[warning] ReadyAPI 无法解析包含了 byte order mark(BOM) 字符的 XML 文档
***<span id="scope-parameter-values">作用域参数值</span>***
| 作用域 | 描述 | 示例 |
| --- | --- | --- |
| #Project# | 项目属性。 | ${#Project#Project property} |
| #TestSuite# | 当前位置的测试套件(测试用例集)属性。 | ${#TestSuite#Suite property} |
| #TestCase# | 当前位置的测试用例属性。 | ${#TestCase#Case property} |
| TestStep# | 当前用例下的测试步骤名称。 | ${REST Request#Response} |
| #[TestSuite#TestCase#TestStep]# | 为了引用其他测试套件或测试用例的属性,使用完整路径来指定期望的作用域。<br>路径被包裹在中括号里:<br>${#[Suite name#Case name#Step name]#Property name} | ${#[Shared suite#Common]#Username} |
| #Global# | 全局属性。<br> **提示:** 你可以忽略该作用域。 | ${#Global#Global Property} <br> 或 <br> ${Global Property} |
| #System# | 系统属性。 <br> **提示:** 点击菜单 **Help** > **System properties** 查看可用的系统属性。 | ${#System#os.name} |
| #Env# | 系统环境变量。 | ${#Env#JAVA_HOME} |
| #MockService# | 在虚拟服务中声明的属性。<br>**提示:** 该作用域仅在 [ServiceV](ServiceV.md) 中可用。 | ${#MockService#virt-service-property} |
| #MockResponse# | 在虚拟响应中声明的属性。<br>**提示:** 该作用域仅在 [ServiceV](ServiceV.md) 中可用。 | ${#MockResponse#Response Property} |
| #SecurityTest# | 在安全测试中声明的属性。<br>**提示:** 该作用域仅在 [Secure](Secure.md) 中可用。 | ${#SecurityTest#Secure Property} |
# 动态表达式
动态属性是属性扩展的一种形式,通过插入 [Groovy](http://book.qadoc.org/groovy) 脚本提供动态数据。如果要在属性扩展中加入 Groovy ,使用下面的语法:
```
${=Groovy code}
```
下面的表达式生成了一个 0 到 999 之间的随机数:
```
${=(int)(Math.random()*1000)}
```
根据使用属性扩展的场景,你可以使用相关脚本对象。比如,在 [request](测试步骤.md) 测试步骤中,你可以使用 `request` 对象:
>[success]`${=request.name}` 表达式计算结果为该 request 测试步骤的名称。
`${=request.operation.interface.project.name}` 表达式的计算结果为项目名称。
几乎在任何脚本中,都可以使用 `log` 对象。
在属性扩展表达式中使用第三方 Jar 包中的类,需要先导入:
```
def b = context.expand('${=import testa.Person;def a = new Person();a.say()}')
```
运行结果:
![m1/TOIMGe6dd10701115055N.jpg](https://img.liyunx.com/m1/TOIMGe6dd10701115055N.jpg)
# 嵌套属性扩展
你可以在另一个表达式中使用属性扩展。
**引用一个包含其他属性扩展的属性:**
<table class="aqTable" cellspacing="0" cellpadding="0">
<thead>
<tr style="background-color: #eee;">
<th class="aqTableHeader">属性</th>
<th class="aqTableHeader">值</th>
<th class="aqTableHeader">计算结果</th>
</tr>
</thead>
<tbody>
<tr>
<td><span style="color : orange; ">PropertyA</span></td>
<td>Hello!</td>
<td>Hello!</td>
</tr>
<tr>
<td><span style="color : red; ">PropExp</span></td>
<td><code><span style="color : orange; ">${#TestCase#PropertyA}</span></code></td>
<td>Hello!</td>
</tr>
<tr>
<td>Result</td>
<td><code><span style="color : red; ">${#TestCase#PropExp}</span></code></td>
<td>Hello!</td>
</tr>
</tbody>
</table>
**属性扩展作为表达式的一部分:**
<table class="aqTable" cellspacing="0" cellpadding="0">
<thead>
<tr>
<th class="aqTableHeader">属性</th>
<th class="aqTableHeader">值</th>
<th class="aqTableHeader">计算结果</th>
</tr>
</thead>
<tbody>
<tr>
<td>PropA</td>
<td>Hello!</td>
<td>Hello!</td>
</tr>
<tr>
<td>PropB</td>
<td>Good Morning!</td>
<td>Good Morning!</td>
</tr>
<tr>
<td><span style="color : blue; ">PropName</span></td>
<td>PropA</td>
<td>PropA</td>
</tr>
<tr>
<td>Result</td>
<td><code>${#TestCase#<span style="color : blue; ">${#TestCase#PropName}</span>}</code></td>
<td>Hello!</td>
</tr>
</tbody>
</table>
**使用属性扩展来指定 XPath 表达式:**
<table class="aqTable" cellspacing="0" cellpadding="0">
<thead>
<tr>
<th class="aqTableHeader">属性</th>
<th class="aqTableHeader">值</th>
<th class="aqTableHeader">计算结果</th>
</tr>
</thead>
<tbody>
<tr>
<td><span style="color : orange; ">xml</span></td>
<td>
<div class="aqCodeSegment">
<div id="IDDITF5MRGV313NJ2CQCEUPZU1RBW5F03U5XRQ5LHAGSCBK3RXJF_divcodeseg" class="aqCodeSegmentInternal">
<p><property><br> <value id="123">Hello!</value><br>
</property></p>
</div>
</div>
</td>
<td>
<div class="aqCodeSegment">
<div id="IDPAJ3IFATKMTLK3DMUCTVAA5DLNON3V5FXHFDTTKRPUR2SJGQKOHC_divcodeseg" class="aqCodeSegmentInternal">
<p><property><br> <value id="123">Hello!</value><br>
</property></p>
</div>
</div>
</td>
</tr>
<tr>
<td><span style="color : red; ">id</span></td>
<td>123</td>
<td>123</td>
</tr>
<tr>
<td><span style="color : blue; ">xpath</span></td>
<td><code>//value[@id=<span style="color : red; ">${#TestCase#id}</span>]/text()</code></td>
<td><code>//value[@id=<span style="color : red; ">123</span>]/text()</code></td>
</tr>
<tr>
<td>Result</td>
<td><code><span style="color : orange; ">${#TestCase#xml<span style="color : blue; ">#${#TestCase#xpath}</span>}</span></code></td>
<td>Hello!</td>
</tr>
</tbody>
</table>
# 脚本中使用属性扩展
你可以在脚本中使用属性扩展。为了在 groovy 脚本中获取属性值,使用下面的语法:
```
def foo = context.expand( 'Property expansion' )
```
下面的代码片段将测试用例属性 *Username* 的值赋值给 foo 变量:
```
def foo = context.expand( '${#TestCase#Username}' )
```
当将属性扩展传递给 `context.expand()` 方法时,ReadyAPI 隐式地用属性扩展的计算结果替换属性扩展本身。假设上面示例中 *username* 属性的值为 `tester` ,得到的表达式如下:
```
def foo = context.expand( 'tester' )
```
同理,你可以通过连接字符串来构造更复杂的表达式:
```
// 假设测试用例有如下属性:
// Username == tester
// ID = 12345
def foo = context.expand ( '${#TestCase#Username} ${#TestCase#ID}' )
// 等价于 foo = context.expand('tester 12345')
def foo = context.expand ( 'mynameis${#TestCase#Username}123' )
// 等价于 foo = context.expand('mynameistester123')
```
# 转义属性扩展
有时你可能需要传递属性扩展本身,而不是解析它。例如,你有一个包含多个属性扩展的数据源,并且想在后续的步骤中才解析这些扩展,而不是立即解析得到结果。
在这种情况下,你需要转义属性扩展。在属性扩展的开始位置添加一个额外的 `$` 符号,保证属性扩展不被解析。在测试运行期间,ReadyAPI 将移除第一个符号,并传递表达式的剩余部分。
比如,如果给出如下表达式:
```
$${#TestCase#Property}
```
ReadyAPI 将传递下面的表达式:
```
${#TestCase#Property}
```
# 注意事项
属性扩展字符串不能使用双引号,因为 ${} 会被 Groovy 解析。
>[danger]错误示例:
```
def a = context.expand("${=(int)(Math.random()*1000)}");
```
>[success]正确示例:
```
def a = context.expand('${=(int)(Math.random()*1000)}');
```
参考资料:
1、[ReadyAPI Documentation / Testing APIs / Using Properties / Property Expansion](https://support.smartbear.com/readyapi/docs/testing/properties/expansion.html)
---
:-: --- 贡献者名单(排名不分先后) ---
:-: **材料**
:-: **编写**
李云
:-: **校验**
:-: **支持**
- 基础知识
- 属性
- 属性分类
- 属性扩展
- Get Data 对话框
- 断言
- 关于断言
- 使用断言
- 断言类型
- Response SLA
- Script
- Property Content Assertions
- Contains
- Equals
- Equals Binary
- JSONPath Count
- JSONPath Existence Match
- JSONPath Match
- JSONPath RegEx Match
- Message Content
- Not Contains
- XPath Match
- XQuery Match
- Compliance Assertions
- Swagger Compliance
- Schema Compliance
- HTTP Header Exists
- HTTP Header Equals
- JDBC Assertions
- 复制断言
- 术语
- 脚本
- 关于脚本
- 脚本编辑器
- JSONPath
- Projects
- SoapUI
- 测试步骤
- Groovy Script
- DataSource
- Conditional GoTo
- REST Request
- ReadyAPI
- 环境
- 关于环境
- 创建环境
- Rest Services
- Custom Properties
- JDBC Connections
- 团队协作
- 集成
- GitLab
- 第三方库
- Groovy 库
- Java 库
- 自定义ReadyAPI
- 首选项
- 全局属性
- ReadyAPI
- Code Templates
- JVM 设置
- 修改
- 实战指导
- 项目属性
- Groovy
- 代码片段
- 开发规范 v0.1
- 属性
- inbox
- FAQ
- 安装配置
- 复合工程
- 修改文件夹或文件名称