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

[JP] Lesson 11 translate #743

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
28 changes: 28 additions & 0 deletions jp/11/00-overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
title: Truffleを使ってスマートコントラクトをテストする
header: Truffleを使ってスマートコントラクトをテストする
roadmap: roadmap.jpg
path: solidity_advanced
position: 1
publishedOn: Cryptozombies
---

よく来たな!前回のレッスンではこれくらいお手の物であることをお前は証明した。

メインネットにゲームをデプロイするがいい。勝利を噛みしめるんだ!

ちょっと待てよ…もしかするとお前は _すでに考えが及んでいるかもしれない_ が。コントラクトをメインネットにデプロイすると、永久に残るだろう。もし何かミスがあれば、それも永久に残ってしまうのだ。まるでアンデッドのゾンビだな。

どれほどスキルが高かろうと、ミスや _**バグ**_ はつきものだ。ゾンビが攻撃すると100%勝利を収めてしまうといったような大きなミスはありえないと思うかもしれないが、起きる時には起きるのだ。

攻撃側が100%勝つなんてゲームとして成り立たないし、面白くもなんともないだろう。こんなバグがあるとお前の作ったゲームは死んだも同然で、新鮮な脳みそでゾンビを墓からおびき出すことができなくなってしまう。

このような恐ろしいことが起きないよう、ゲームをあらゆる面からテストする必要がある。

このレッスンを終えると、できるようになることだ:

- `Truffle` + `Ganache` を使ってスマートコントラクトをテストする
- `Chai` を使ってアサーションの表現力を上げる
- `Loom` 上でテストする😉

早速取り掛かるぞ!
66 changes: 66 additions & 0 deletions jp/11/01.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
title: セットアップ
actions: ['答え合わせ', 'ヒント']
requireLogin: true
skipCheckAnswer: false
material:
terminal:
help:
You should probably run `touch test/CryptoZombies.js`😉
commands:
"touch test/CryptoZombies.js":
hint: touch test/CryptoZombies.js
output: |
---
このレッスンでは、 **Truffle** 、 **Mocha** および **Chai** に注目して、 **イーサリアム** のスマートコントラクトをテストするのに必要な原理を説明しよう。これらのレッスンを最大限理解するためには、 **Solidity** と **JavaScript** の中レベルの知識が必要だぞ。

もし **Solidity** が初めてか復習したい時は、<a href="https://cryptozombies.io/lesson/1" target=_blank>最初のレッスン</a>から始めるといい。

もし **JavaScript** に不安があるなら、他でチュートリアルをやってからこのレッスンに戻ってくるといい。


## 我々のプロジェクトを覗いてみよう

前回のレッスンを受けていれば、ゾンビゲームの準備がおおむねできているはずだ。ファイル構成は次のようになっているだろう:

```
├── build
├── contracts
├── Migrations.json
├── CryptoZombies.json
├── erc721.json
├── ownable.json
├── safemath.json
├── zombieattack.json
├── zombiefactory.json
├── zombiefeeding.json
├── zombiehelper.json
├── zombieownership.json
├── contracts
├── Migrations.sol
├── CryptoZombies.sol
├── erc721.sol
├── ownable.sol
├── safemath.sol
├── zombieattack.sol
├── zombiefactory.sol
├── zombiefeeding.sol
├── zombiehelper.sol
├── zombieownership.sol
├── migrations
└── test
. package-lock.json
. truffle-config.js
. truffle.js
```

`test` フォルダを見えるか?これからここにテストを置くぞ。

_Truffle_ では _JavaScript_ と _Solidity_ でのテストがサポートされている。しかし、このレッスンでは簡単な _JavaScript_ を扱っていこう。


# さあテストだ

練習がてらコントラクトごとにテストファイルを分け、ファイル名をそれぞれのコントラクトの名称にする。長い目で見たときに簡単にテストを対応づけられるぞ。特にプロジェクトが大きく育って変化していった時に有用だ。

1. 右のターミナルで、`touch test/CryptoZombies.js`コマンドを叩け。
77 changes: 77 additions & 0 deletions jp/11/02.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
title: セットアップ (続き)
actions: ['答え合わせ', 'ヒント']
requireLogin: true
material:
editor:
language: javascript
startingCode:
"test/CryptoZombies.js": |
answer: >
const CryptoZombies = artifacts.require("CryptoZombies");

contract("CryptoZombies", (accounts) => {
it("should be able to create a new zombie", () => {

})
})

---
どんどん行くぞ。このチャプターでは、テストを書いて実行できるようセットアップを続けるぞ。

## ビルドアーティファクト

スマートコントラクトをコンパイルするたびに、 _Solidity_ のコンパイラーはコントラクトをバイナリー形式に変換したJSONファイル( **ビルドアーティファクト** として参照される)を作成し、 `build/contracts` フォルダーに保存している。

続いてマイグレーションを実行すると、 _Truffle_ がこのファイルを更新して、ネットワークの情報を付加する。

新しいテストスイートの書き出しは、テスト対象のコントラクトのビルドアーティファクトをロードするところから始める。こうすることで、 **Truffle** はコントラクトが理解できるような形式で関数の呼び出し部分をフォーマットする方法を知ることができるのだ。

簡単な例を見せよう。

`MyAwesomeContract` というコントラクトがあるとする。そのビルドアーティファクトをロードするには、こんな風に書く:

```javascript
const MyAwesomeContract = artifacts.require(“MyAwesomeContract”);
```

この関数は **_コントラクトの抽象化_** と呼ばれるものを返す。一言で言えば、 **イーサリアム** との複雑性なやり取りを隠蔽し、 _Solidity_ で書いたスマートコントラクトに対して _JavaScript_ の便利なインターフェースを提供している。次のチャプターで使うぞ。

### contract() 関数

裏側では、 **Truffle** はテストをシンプルにするために **Mocha** の周囲を薄くラップしている。我々のコースは **イーサリアム** の開発に注力していることから、 _Mocha_ について時間をかけて説明することは控える。 _Mocha_ を深掘りしたければ、このレッスンが終わった後にでも<a href="https://mochajs.org/" target=_blank>Mochaのサイト</a>をチェックするといい。今はここで説明していることを理解すればいい - 使い方:

- `contract()`という名の関数を呼び出すことで行われる **グループテスト** 。 **Mocha** の `describe()` を拡張したもので、**テストに必要なアカウントのリスト** とクリーンアップを提供する。

`contract()` は2つの引数を持つ。一つ目は、`string`型のテスト対象だ。二つ目は、`callback` で、ここに実際のテストコードを書く。

- **実行**: `it()` という関数を呼び出して行う。これも2つの引数を持つ: テストが何をするかを説明する `string` と `callback` だ。

まとめると、テストはこのようになる:

```javascript
contract("MyAwesomeContract", (accounts) => {
it("should be able to receive Ethers", () => {
})
})
```

> 注: よく考えられているテストは、コードが実際に何をするか説明している。テストスイートの説明文とテストケースは **一貫した内容** になるよう心掛けるのだ。ドキュメントを書く時と同じだな。

テストは全てこのパターンに従って書くように。なんてことないだろう?😁

# さあテストだ

`CryptoZombies.js` の空のファイルを作っておいてやったから、これを埋めていくぞ。

1. 1行目は `CryptoZombies` という名の `const` を宣言し、`artifacts.require` 関数の戻り値を代入せよ。引数にはテスト対象のコントラクト名を渡すんだ。

2. 次に上からテストコードをコピペせよ。

3. `contract()` の呼び出しを修正し、最初のパラメータに我々のスマートコントラクトの名称を渡せ。

> 注: `accounts` は気にするな。次のチャプターで説明する。

4. `it()` 関数の最初の引数(上記の例では"should be able to receive Ethers"となっている)は、テストの名称であるべきだ。新しいゾンビを作るところから始めるので、最初の引数は"should be able to create a new zombie"となる。

準備はできた。次のチャプターにいくぞ。
71 changes: 71 additions & 0 deletions jp/11/03.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
title: 最初のテスト - 新しいゾンビを生み出す
actions: ['答え合わせ', 'ヒント']
requireLogin: true
material:
editor:
language: javascript
startingCode:
"test/CryptoZombies.js": |
const CryptoZombies = artifacts.require("CryptoZombies");
contract("CryptoZombies", (accounts) => {
//1. initialize `alice` and `bob`
it("should be able to create a new zombie", () => { //2 & 3. Replace the first parameter and make the callback async
})
})

answer: >
const CryptoZombies = artifacts.require("CryptoZombies");

contract("CryptoZombies", (accounts) => {
let [alice, bob] = accounts;
it("should be able to create a new zombie", async () => {
})
})


---

**イーサリアム** にデプロイする前に、ローカルでスマートコントラクトをテストするべきだ。

それには<a href="https://truffleframework.com/ganache" target=_blank>Ganache</a>というツールが使えるぞ。 **イーサリアム** のネットワークをローカル環境に作ってくれる。

_Ganache_ を起動すると、10個のテスト用アカウントと、それぞれのアカウントに100イーサずつ準備してくれるので簡単にテストできるようになる。 _Ganache_ と _Truffle_ は統合されたから、我々はこれらのアカウントに `accounts` を通してアクセスできる。前回のチャプターで触れたやつだ。

しかし `accounts[0]` や `accounts[1]` と書くと、テストコードの可読性が悪くなるな?

可読性を上げるため、2つの名称を使う - アリスとボブだ。さあ、`contract()` 関数内で定義するぞ:

```javascript
let [alice, bob] = accounts;
```
> 注: 貧相な文法については許してくれ。 _JavaScript_ では変数名は小文字を使うと規約で決まっているのだ。

なぜアリスとボブなのか?それには大いなる伝統があるんだ。アリスとボブまたは"A と B"は暗号や物理学、プログラミングなど様々な分野で使われてきた。ここでは簡単に説明したが、興味深い歴史があるぞ。このレッスンが終わった後<a href="http://cryptocouple.com/" target=_blank>読んで</a>みるといい。

さあ最初のテストをするぞ。

## 新しいゾンビを生み出す

アリスが我々の素晴らしいゲームをプレイしたいそうだ。それであれば彼女が最初にしたいことは **自分のゾンビを生み出す🧟** ことだろう。そのためにフロントエンド(または我々のケースでは _Truffle_ )は `createRandomZombie` 関数を呼ばなければならない。

> 注: 参考までにコントラクトの _Solidity_ のコードを載せる:

```sol
function createRandomZombie(string _name) public {
require(ownerZombieCount[msg.sender] == 0);
uint randDna = _generateRandomDna(_name);
randDna = randDna - randDna % 100;
_createZombie(_name, randDna);
}
```

この関数をテストするところから始めよう。

# さあテストだ

1. `contract()` 関数の1行目に、 `alice` と `bob` の2つの変数を定義するぞ。さっき見せた通りだ。

2. 次に、 `it()` 関数を適切に呼び出したい。2つ目の引数( `callback` 関数)はブロックチェーンと「会話」する。つまりこの関数は非同期だということだ。 `async` キーワードが必要だぞ。 `await` キーワードをつけて呼び出せば、テストは処理が終わって戻り値が帰ってくるまで待つようになる。

> Promise がどのように動作するかはこのレッスンの範囲外だ。このレッスンが終わったら、<a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise" target=_blank>公式ドキュメント</a>を読んで知識を深めるといいぞ。
79 changes: 79 additions & 0 deletions jp/11/04.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
title: 最初のテスト - 新しいゾンビを生み出す(続き)
actions: ['答え合わせ', 'ヒント']
requireLogin: true
material:
editor:
language: javascript
startingCode:
"test/CryptoZombies.js": |
const CryptoZombies = artifacts.require("CryptoZombies");
const zombieNames = ["Zombie 1", "Zombie 2"];
contract("CryptoZombies", (accounts) => {
let [alice, bob] = accounts;
it("should be able to create a new zombie", async () => {
// start here
})
})

answer: >
const CryptoZombies = artifacts.require("CryptoZombies");

const zombieNames = ["Zombie 1", "Zombie 2"];

contract("CryptoZombies", (accounts) => {
let [alice, bob] = accounts;
it("should be able to create a new zombie", async () => {
const contractInstance = await CryptoZombies.new();
})
})

---

いいぞ!これで最初のテストで使うシェルができた。テストの書き方を見せてやろう。

Usually, every test has the following phases:

通常、テストは次のフェーズで構成される:

1. **_セットアップ_**: 状態やインプットを定義する場所だ。

2. **_動作_**: コードをテストする場所だ。 _1つのことだけテストする_ ことに気をつけろ。

3. **_アサート_:** 結果をチェックする場所だ。

テストコードで何をすべきかさらに細かく見ていこう。

## 1. セットアップ

チャプター2で _コントラクトの抽象化_ を作ったな。しかしその名が示す通り、これは抽象化にすぎない。スマートコントラクトと実際に対話するためには、コントラクトの **インスタンス** として動作する _JavaScript_ のオブジェクトを作らなければならない。 `MyAwesomeContract` の例で、 _コントラクトの抽象化_ を用いてインスタンスを作る方法はこうだ:

```javascript
const contractInstance = await MyAwesomeContract.new();
```

よし。さて次は?

`createRandomZombie` を呼び、ゾンビの名前を引数として渡すぞ。そう、次のステップではアリスのゾンビに名前をつけなければならない。“Alice’s Awesome Zombie” でどうだ。

しかし、テストの度にこれをするとコードが汚くなっていまう。より良いアプローチとして、グローバル配列に定義する方法がある:

```javascript
const zombieNames = ["Zombie #1", "Zombie #2"];
```

コントラクトのメソッドを呼ぶ時にこう使う:

```javascript
contractInstance.createRandomZombie(zombieNames[0]);
```

> 注: ゾンビの名前を配列に格納する方法は重宝するぞ。例えば、1体や2体ではなく1000体のゾンビを作ろうとした時だ😉。

# さあテストだ

お前のために `zombieNames` 配列を準備しておいたからな。

1. コントラクトのインスタンスを作るぞ。 `contractInstance` という名の `const` を定義し、 `CryptoZombies.new()` 関数の結果を代入するんだ。

2. `CryptoZombies.new()` はブロックチェーンと「対話」する。つまり非同期の関数だ。関数を呼び出すところに `await` キーワードをつけるぞ。
Loading