Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

writing-automated-tests translation #7

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 59 additions & 59 deletions components/learn/modules/ROOT/pages/writing-automated-tests.adoc
Original file line number Diff line number Diff line change
@@ -1,99 +1,99 @@
= Writing Automated Smart Contract Tests
= 编写智能合约自动化测试

In a blockchain environment, a single mistake could cost you all of your funds - or even worse, your users' funds! This guide will help you develop robust applications by writing automated tests that verify your application behaves exactly as you intended.
在区块链环境中,一个错误可能花费掉你所有的资金——甚至更糟,它会花费掉你用户的资金!这个指南将会帮助你开发健壮的应用程序,通过编写自动化测试来检测应用是不是像你预期的那样运行。

We'll cover the following topics:
我们接下来将会讨论以下话题:

* <<setting-up-a-testing-environment, Setting up a Testing Environment>>
* <<writing-unit-tests, Writing Unit Tests>>
* <<performing-complex-assertions, Performing Complex Assertions>>
* <<setting-up-a-testing-environment, 配置测试环境>>
* <<writing-unit-tests, 编写单元测试>>
* <<performing-complex-assertions, 执行复杂的命令>>

=== About Testing
=== 关于测试

There is a a wide range of testing techniques, from xref:deploying-and-interacting.adoc#interacting-from-the-command-line[simple manual verifications] to complex end-to-end setups, all of them useful in their own way.
测试技术有很多种,从 xref:deploying-and-interacting.adoc#interacting-from-the-command-line[简单的手动验证] 到复杂的端到端设置,每种方式都有它们的用处。

When it comes to smart contract development though, practice has shown that contract https://en.wikipedia.org/wiki/Unit_testing[_unit testing_] is exceptionally worthwhile. These tests are simple to write and quick to run, and let you add features and fix bugs in your code with confidence.
当涉及到智能合约开发时,经验表明对合约的 https://en.wikipedia.org/wiki/Unit_testing[_单元测试_] 是值得期待的。这些测试都很容易编写,并且运行很快,同时你可以很容易地给代码增加特征或是修改漏洞。

Smart contract unit testing consists of multiple small, focused tests, which each check a small part of your contract for correctness. They can often be expressed in single sentences that make up a specification, such as 'the admin is able to pause the contract', 'transferring tokens emits an event' or 'non-admins cannot mint new tokens'.
智能合约单元测试包括多种小规模的针对性测试,它们可以检查合约中每一个小部分的正确性。可以使用单独的句子将测试规范表达出来,例如“管理员可以暂停合约”,“转移代币会触发事件”或者“非管理员不能挖矿获得新币”。

[[setting-up-a-testing-environment]]
== Setting up a Testing Environment
== 配置测试环境

You may be wondering _how_ we're going to run these tests, since smart contracts are executed inside a blockchain. Using the actual Ethereum network would be very expensive, and while testnets are free, they are also slow (with blocktimes between 5 and 20 seconds). If we intend to run hundreds of tests whenever we make a change to our code, we need something better.
因为智能合约必须要在区块链上执行,所以你也许想知道我们将要 _怎样_ 运行这些测试用例。使用实际的以太坊网络费用很高,测试网络是免费的,但它很慢(出块时间在5到20秒之间)。如果我们想要在每一次修改代码后运行成百上千个测试用例,那么我们还需要找到更适合的测试网络。

What we will use is called a _local blockchain_: a slimmed down version of the real thing, disconnected from the Internet, running on your machine. This will simplify things quite a bit: you won't need to get Ether, and new blocks will be mined instantly.
我们将要使用的就是 _本地区块链_ :它是一个以太坊真实版本的精简版,运行在你的电脑上,并且没有与互联网连接。这将简化很多事情:你不需要获取以太币,也能很快挖出新块。

To aid us in this we'll use the xref:test-environment::index.adoc[*OpenZeppelin Test Environment*], a JavaScript library that will take care of setting up our local blockchain.
为了帮助我们测试,我们将会使用 xref:test-environment::index.adoc[*OpenZeppelin测试环境*],它是一个JavaScript库,可以帮助我们设置本地区块链。

NOTE: If you've read the xref:deploying-and-interacting.adoc#local-blockchain[Deploying and Interacting] guide, you will already be familiar with https://github.com/trufflesuite/ganache-cli/[Ganache]. This is what Test Environment uses under the hood, taking care of its configuration for you.
NOTE: 如果你已经阅读了 xref:deploying-and-interacting.adoc#local-blockchain[部署和交互],你应该已经熟悉了 https://github.com/trufflesuite/ganache-cli/[Ganache]。这就是测试环境在底层的用处,它可以帮助你管理配置。

To install the OpenZeppelin Test Environment, run:
下载OpenZeppelin测试环境,运行以下命令:

```console
$ npm install --save-dev @openzeppelin/test-environment
```

Once you `require` the library from your JavaScript code, it will automatically run a local testing blockchain for you. It also exports a list of accounts that have been pre-funded with Ether and convenient ways to load your contracts from their compiled artifacts, among other utilities.
一旦你 `require` 了自己的JavaScript代码库,它将会自动运行一个本地测试链。它将会输出一个账户列表,列表中的账户都预先充值了Ether。还会列出通过编译后的文件和通过其他实体来加载合约的简便方法。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utilities -> 通常是指 帮助工具(函数)。


```javascript
const { accounts, contract } = require('@openzeppelin/test-environment');

// Use the different accounts, which are unlocked and funded with Ether
// 使用不同解锁且有资产的账户
const [ admin, deployer, user ] = accounts;

// Create a contract object from a compilation artifact
// 使用artifact创建一个合约对象
const MyContract = contract.fromArtifact('MyContract');
```

For detailed information on these exported values and their usage, refer to Test Environment's xref:test-environment::api.adoc[API reference].
如果你想要更加详细的了解输出的值和它们的用处,那么可以查看测试环境的 xref:test-environment::api.adoc[API参考].

[[writing-unit-tests]]
== Writing Unit Tests
== 编写单元测试

In order to actually run your tests, you will need to also install a JavaScript _test runner_. You are free to use any of the xref:test-environment::choosing-a-test-runner.adoc[recommended ones]: for this guide, we'll pick https://mochajs.org/[Mocha] with https://www.chaijs.com/[Chai] assertions.
为了实际运行你的测试实例,你需要下载JavaScript的 _test runner_。你可以使用 xref:test-environment::choosing-a-test-runner.adoc[推荐列表] 中的任何一个:在本指南中,我们将选择 https://mochajs.org/[Mocha] https://www.chaijs.com/[Chai]

```console
$ npm install --save-dev mocha chai
```

Create a `test` directory: this is where you will keep your test files. These are best structured by mirroring xref:developing-smart-contracts.adoc#setting-up-a-solidity-project[the `contracts` directory]: for each `.sol` file there, create a corresponding `.test.js` file.
新建一个 `test` 目录:用来存放你的测试文件。最好的构建这些文件的方法就是通过镜像 xref:developing-smart-contracts.adoc#setting-up-a-solidity-project[`contracts`目录]:对 `contracts` 目录中的每一个 `.sol` 文件,都创建一个对应的 `.test.js` 文件。

Time to write our first tests! These will test properties of the `Box` contract xref:developing-smart-contracts.adoc#box-contract[from previous guides]: a simple contract that lets you `retrieve` a value the owner previously `store` d.
现在到了编写我们第一个测试的时候了!我们将会测试 xref:developing-smart-contracts.adoc#box-contract[前面指南中出现的] `Box` 合约的属性:这个合约使你可以 `获取` 合约所有者预先 `存储` 在变量中的值。

```javascript
// test/Box.test.js

// Load dependencies
// 加载依赖
const { accounts, contract } = require('@openzeppelin/test-environment');
const { expect } = require('chai');

// Load compiled artifacts
// 加载已编译的artifacts
const Box = contract.fromArtifact('Box');

// Start test block
// 开始测试模块
describe('Box', function () {
const [ owner ] = accounts;

beforeEach(async function () {
// Deploy a new Box contract for each test
// 为每个测试部署一个新的Box合约
this.contract = await Box.new({ from: owner });
});

// Test case
// 测试用例
it('retrieve returns a value previously stored', async function () {
// Store a value - recall that only the owner account can do this!
// 存储一个值——记得只有所有者账户才能执行此操作!
await this.contract.store(42, { from: owner });

// Test if the returned value is the same one
// Note that we need to use strings to compare the 256 bit integers
// 如果返回值是相同的就进行测试
// 注意我们需要使用字符串的格式与256位int类型做比较
expect((await this.contract.retrieve()).toString()).to.equal('42');
});
});
```

TIP: Many books have been written about how to structure unit tests: for a quick reference, check out the https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/test[tests for OpenZeppelin Contracts], or the following https://medium.com/coinmonks/how-to-test-ethereum-smart-contracts-ac28fa852281[guide for ERC20 tests].
TIP: 很多书籍都写过如何将单元测试结构化:想要获取此类参考,可以查看 https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/test[OpenZeppelin合约的测试],或者接下来的 https://medium.com/coinmonks/how-to-test-ethereum-smart-contracts-ac28fa852281[ERC20测试指南].

We are now ready to run our tests! The best way to do this is by adding a `test` script to your `package.json`:
现在我们准备好运行测试了!最好的方式就是给 `package.json` 添加一个 `test` 脚本:

[source,diff]
----
Expand All @@ -102,7 +102,7 @@ We are now ready to run our tests! The best way to do this is by adding a `test`
}
----

With this, running `npm test` will execute all tests in the `test` directory, checking that your contracts work the way you meant them to:
有了这个脚本,运行 `npm test` 命令就可以执行 `test` 目录下所有的测试了,这样就可以检查合约是否按照我们希望的那样运行:

```console
$ npm test
Expand All @@ -112,25 +112,25 @@ $ npm test

[TIP]
====
Don't forget to re-compile your contracts if you make changes to them! If you want to do this automatically on each test run, set your `test` script instead to:
如果你修改了合约,别忘了要重新编译!如果你希望在每个测试之前自动重新编译,那么可以将 `test` 脚本设置为:

`oz compile && mocha --exit --recursive test`
====

Test Environment comes with sensible defaults that should work for most use-cases, but you can always xref:test-environment::getting-started.adoc#configuration[configure] it to provide more accounts or use different kinds of contract objects, among others.
测试环境的默认值是可以修改的,默认的参数适用于大多数场景,但是你也可以 xref:test-environment::getting-started.adoc#configuration[设置] 参数来让它提供更多的账户,或者使用不同种类的合约对象。

It's also a very good idea at this point to set up a Continuous Integration service such as https://circleci.com/[CircleCI] to make your tests run automatically every time you commit your code to GitHub.
同时,也可以设置持续集成服务,例如 https://circleci.com/[CircleCI]。这样可以在你每次提交代码到GitHub后自动运行测试。

[[performing-complex-assertions]]
== Performing Complex Assertions
== 执行复杂命令

Many interesting properties of your contracts may be hard to capture, such as:
合约中很多有趣的属性很难获取到,例如:

* verifying that the contract reverts on errors
* measuring by how much an account's Ether balance changed
* checking that the proper events are emitted
* 验证合约是否因错误导致回滚
* 判断一个账户的以太币余额变化了多少
* 检查是否触发了正确的事件

xref:test-helpers::index.adoc[*OpenZeppelin Test Helpers*] is a library designed to help you test all of these properties. It will also simplify the tasks of simulating time passing on the blockchain and handling very large numbers.
xref:test-helpers::index.adoc[*OpenZeppelin 测试助手*] 是一个可以帮助你测试这些属性的库。它将会简化在区块链上模拟时间的任务,同时它也可以处理大量任务。

```console
$ npm install --save-dev @openzeppelin/test-helpers
Expand All @@ -142,15 +142,15 @@ $ npm install --save-dev @openzeppelin/test-helpers
const { accounts, contract } = require('@openzeppelin/test-environment');
const { expect } = require('chai');

// Import utilities from Test Helpers
// 从测试帮助导入实体
const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');

const Box = contract.fromArtifact('Box');

describe('Box', function () {
const [ owner, other ] = accounts;

// Use large integers ('big numbers')
// 使用大整数 ('big numbers')
const value = new BN('42');

beforeEach(async function () {
Expand All @@ -160,19 +160,19 @@ describe('Box', function () {
it('retrieve returns a value previously stored', async function () {
await this.contract.store(value, { from: owner });

// Use large integer comparisons
// 使用大整数比较
expect(await this.contract.retrieve()).to.be.bignumber.equal(value);
});

it('store emits an event', async function () {
const receipt = await this.contract.store(value, { from: owner });

// Test that a ValueChanged event was emitted with the new value
// 测试新的值将会触发一个ValueChanged事件
expectEvent(receipt, 'ValueChanged', { newValue: value });
});

it('non owner cannot store a value', async function () {
// Test a transaction reverts
// 测试交易回滚
await expectRevert(
this.contract.store(value, { from: other }),
'Ownable: caller is not the owner'
Expand All @@ -181,11 +181,11 @@ describe('Box', function () {
});
```

No configuration is required: Test Environment will detect the Test Helpers and do the hard work for you.
不需要任何配置:测试环境将会发现测试助手然后帮助你完成复杂的工作。

These will test properties of the `Box` contract xref:developing-smart-contracts.adoc#using-openzeppelin-contracts[from previous guides]: a simple contract that lets you `retrieve` a value the owner previously `store`d.
这些将测试 xref:developing-smart-contracts.adoc#using-openzeppelin-contracts[先前的指南中的] `Box` 合约的属性:这是一个简单的合约,可以 `检索` 所有者先前 `存储` 的值。

Run your tests again to see the Test Helpers in action:
再次运行你的测试就可以看到测试助手正在运行:

```console
$ npm test
Expand All @@ -195,14 +195,14 @@ $ npm test
✓ non owner cannot store a value
```

The Test Helpers will let you write powerful assertions without having to worry about the low-level details of the underlying Ethereum libraries. To learn more about what you can do with them, head to their xref:test-helpers::api.adoc[API reference].
测试助手将会帮助你编写有效的命令,这样你就不用担心以太坊库中的底层细节。想要知道它还有什么用处,可以查看它的 xref:test-helpers::api.adoc[API参考]。

TIP: The OpenZeppelin Test Environment is not required to use the Test Helpers: to learn how to use them standalone or integrated in other systems, refer to their xref:test-helpers::configuration.adoc[documentation].
TIP: 使用测试助手不需要OpenZeppelin测试环境:要了解如何独立使用它们或将其集成到其他系统中,可以参考 xref:test-helpers::configuration.adoc[文档]。

== Next Steps
== 下一步

Once you have thoroughly tested your contracts and are reasonably sure of their correctness, you'll want to deploy them to a real network and start interacting with them. The following guides will get you up to speed on these topics:
一旦对合约进行了全面的测试并确定了合约的正确性,接下来就需要将其部署到真实的网络并开始与它们进行交互。以下指南可帮助你快速掌握这些问题:

* xref:connecting-to-public-test-networks.adoc[Connecting to Public Test Networks]
* xref:deploying-and-interacting.adoc[Deploying and Interacting]
* xref:preparing-for-mainnet.adoc[Preparing for Mainnet]
* xref:connecting-to-public-test-networks.adoc[连接到公共测试网络]
* xref:deploying-and-interacting.adoc[开发和交互]
* xref:preparing-for-mainnet.adoc[准备主网]