> For the complete documentation index, see [llms.txt](https://gushi10546.gitbook.io/aptos-kai-fa-zhe-wen-dang/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://gushi10546.gitbook.io/aptos-kai-fa-zhe-wen-dang/guides-zhi-nan/move-jiao-cheng/move-shi-wu-ce-shi.md).

# Move 事务测试

{% hint style="info" %}
**处于探索阶段的功能**&#x20;

本文档中描述的 Move 事务测试功能处于探索阶段。对它的支持将取决于 Aptos 社区对它的使用。
{% endhint %}

如果你是一个使用 Move 语言的智能合约开发者，那么你可以使用 Move 事务测试来编写和运行端到端的测试。

本教程将指导你[使用 Aptos CLI ](/aptos-kai-fa-zhe-wen-dang/aptos-cli/shi-yong-aptos-cli.md)编写和运行端到端的 Move 事务测试的步骤。

与 Move 单元测试相比，Move 事务测试有助于验证模块内代码的正确性，Move 事务测试使你能够测试更广泛的用例，如发布 Move 模块和模块间的交互。

### 概述

参考 `aptos_test_harness` [GitHub 文件夹](https://github.com/aptos-labs/aptos-core/tree/main/aptos-move/aptos-transactional-test-harness/tests/aptos_test_harness)，了解 Move 事务测试的大概样子。

一个 Move 事务测试套件由两种类型的文件组成：

* Move 文件，以 `.move` 为扩展名。这些 Move 文件包含了事务测试。事务测试的执行方法是一系列 Rust [clap](https://docs.rs/clap/latest/clap/)（命令行参数解析器）命令。它们在 Move 文件中被写成注释。为了区别于正常的 Move 注释，这些事务测试命令的前缀是一个特殊的注释字符串指标 `//#`。
* 基线文件，以 `.exp` 为扩展名。当你第一次运行 `aptos` CLI时，这些基线文件将被创建为空。如果你第一次用 `UB=1` 选项运行测试，基线文件将被填充为测试输出。

### 快速开始

在你进入细节之前，你可以按照下面的步骤来运行一个 Move 事务测试示例，看看结果。

#### Step 1: 安装 Aptos CLI

确保你已经安装了 `aptos`，即 Aptos CLI 工具。关于如何安装和使用 aptos CLI 工具，请参阅 [Aptos CLI](/aptos-kai-fa-zhe-wen-dang/aptos-cli.md)。

#### Step 2: 运行 Move 事务测试套件

* 克隆或下载 `aptos-core` [GitHub repo](https://github.com/aptos-labs/aptos-core.git)。
* Move 事务测试套件位于 `aptos-core/aptos-move/aptos-transactional-test-harness/test`s。
* 运行 `aptos` CLI 命令，选项为 `move transactional-test。`

{% hint style="info" %}
💡 使用 **UB=1**

当你运行 `aptos` CLI命令时，确保在**第一次或你已经更新了测试时，**&#x5728;命令中包含 `UB=1`，如下所示。
{% endhint %}

```
UB=1 aptos move transactional-test --root-path aptos-core/aptos-move/aptos-transactional-test-harness/test
```

* `-root-path` 指定了所有测试的位置。
* 测试运行器沿着目录层级往下走，在名称以 `.move` 或 `.mvir` 结尾，且带有特殊前缀 `//#` 的注释文件中找到测试。
* Move 事务测试运行器运行测试并将测试的输出与基线文件进行比较。基线文件保存了第一次运行时产生的结果的内容。

### 🌰 举个栗子

本节介绍了如何编写和运行各种 Move 事务测试命令的例子。

#### 创建账号

```
//# create_account —name Alice [--initial-coins 10000]
```

`create_account` 命令将生成一个确定的私钥、公钥对，并创建一个带名称的账户地址（上例中的 Alice）。

{% hint style="info" %}
💡 账户中的默认余额 可以指定账户的默认代币余额，否则，将使用默认值 10000。
{% endhint %}

#### Publish modules

```
//# publish [--gas-budget 100]
module Alice::first_module {
    public entry fun foo() {
        return
    }
}
```

`publish` 命令将一个 Move 模块发布到一个指定的账户（上例中为**Alice**）。可以选择通过 `--gas-budget` 指定发布操作中，允许消耗的最大 gas 单位。

{% hint style="info" %}
💡 `--gas-budget` 默认值 默认取当前账户所持有的代币余额
{% endhint %}

#### 运行模块中脚本函数

```
//# run --signers Alice [--args x"68656C6C6F20776F726C64"] [--type-args "0x1::aptos_coin::AptosCoin"] [--expiration 1658432810] [--sequence-number 1] [--gas-price 1] [--show-events] -- Alice::first_module::function_name
```

`run`命令通过发送一个事务来运行模块中脚本函数。

在上面的例子中:

* `-signers`指定谁签署和发送交易。
* `Alice::first_module::function_name`是 Alice 地址下，first\_module 模块函数的名称。
* `-args` 指定要传递给脚本函数的入参。
* `-type-args`如果脚本函数是一个泛型函数，则指定类型参数。
* `-expiration`交易过期时间。
* `-sequence-number`账户序列号。
* `-gas-price`单位 gas 的费用。
* `-show-events`如果指定，打印出交易事件。

#### 执行脚本

```
//# run --script --signers Alice [--args x"68656C6C6F20776F726C64"] [--type-args "0x1::aptos_coin::AptosCoin"] [--expiration 1658432810] [--sequence-number 1] [--gas-price 1]
script {
    use aptos_framework::coin;
    use aptos_framework::aptos_coin::AptosCoin;

    fun main(sender: &signer, receiver: address, amount: u64) {
        coin::transfer<AptosCoin>(sender, receiver, amount);
    }
}
```

`run` 命令也可以和 `--script` 选项一起使用，以执行一个脚本。

#### 查看模块下的资源

```
//# view --address Alice --resource Alice::first_module::resource_name
```

`view`打印出在一个地址下的资源。

* `--address`：打印指定账户下的资源
* `--resource`：打印该账户地址下的指定资源

#### View tables

```
//# view_table --table_handle 5713946181763753045826830927579154558 --key_type 0x1::string::String --key_value x"68656C6C6F20776F726C64" --value_type 0x1::token::Collection
```

`view_table` 通过表格的 key 来打印出表内的一个值。例如，在下面的 Move 代码中。

```
struct Collections has key {
    collections: Table<string::String, Collection>,
}
```

* 在存储中，表`collections`有一个句柄存储在资源`Collections`中。
* 要按键查询一个表项，我们需要知道表的句柄信息`-table_handle 5713946181763753045826830927579154558`。
* `table_handle` 是要查询的表的句柄。它可以通过`view_resource`命令查询。
* `-key_type`是键的类型信息。要获得一个键的值，请使用`-view_table`选项和`-key_type`及`-key_value`。
* `-key_value`是用于检索值的键。
* `key_type` 用于对 `key_value` 进行反序列化，以获得一个原始键，可以用来查询存储。
* `-value_type`是用于反序列化表值的类型信息。存储的返回值也必须被反序列化才有用。因此在测试过程中，也需要 `-value_type`。
