# 単体テスト

単体テストを使用して、コードベース内の各コンポーネントが期待通りに正しく動作することを確認します。

## 参考文献

これは、同様の技術スタックを使用した[単体テストに関する良い、迅速な入門ガイド](https://codeburst.io/javascript-unit-testing-using-mocha-and-chai-1d97d9f18e71)と、[もっと詳細なガイド](https://blog.logrocket.com/a-quick-and-complete-guide-to-mocha-testing-d0e0ea09f09d)です。

## すべての単体テストを実行する

リポジトリのルートディレクトリで、ターミナルに以下のコマンドを入力します：

```shellsession
$ npm test
```

## テストカバレッジ

テストを実行するたびに、テストスイートがカバーしたソースコードファイルのどの部分かを詳細に説明するカバレッジレポートが生成されます。これにより、コードベースのどれくらいがテストされているかがわかります。

テストを実行した後、サマリーが出力され、`coverage/index.html`のパスで詳細なレポートを任意のウェブブラウザで見ることができます。Macのターミナルでは、`open coverage/index.html`コマンドを実行して、デフォルトのウェブブラウザでこのページを開くことができます。また、テストを実行した後に`npx nyc report --reporter=text`コマンドをターミナルで使用して、カバレッジレポートを見ることもできます。

### 単一のテストスイートを実行する

単一のテストやテストグループを実行するには、`.js`ファイル内の`suite`または`test`の後ろに`.only`を追加し、上記のコマンドを使用してテストを実行します。

**`.only`が含まれるコードをコミットしないでください！**（私たちのCIが_すべて_の単体テストを実行することを望んでいます。）

#### 例

"p5.ColorConversion"のテストスイートのみを実行するには、`test/unit/color/color_conversion.js`ファイルの最初の行を変更する必要があります：


```js
suite.only('color/p5.ColorConversion', function() {
```

## テストカバレッジ

テストを実行するたびに、テストスイートがカバーしたソースコードファイルのどの部分を詳細に説明するカバレッジレポートが生成されます。これにより、コードベースのどの部分がテストされているかがわかります。

テストを実行した後、サマリーが出力され、任意のウェブブラウザで詳細なレポートを`coverage/index.html`のパスで見ることができます。Macのターミナルでは、`open coverage/index.html`コマンドを実行して、デフォルトのウェブブラウザでこのページを開くことができます。また、`npx nyc report --reporter=text`コマンドをターミナルで使用して、テストを実行した後にカバレッジレポートを表示することもできます。

### テストスイートをスキップする

この機能は`.only()`とは逆の動作をします。`.skip()`を追加することで、Mochaに特定のテストスイートやテストケースを無視させることができます。スキップされたものはペンディングとしてマークされ、ペンディングとしてレポートされます。

## インフラストラクチャ

### フレームワーク

私たちは[mocha](https://mochajs.org)を使って、単体テストを整理し、実行しています。

[chaiの`assert`（および`expect`）](https://www.chaijs.com/api/assert/)を使用して、コードがどのように動作すべきかに関する個々の声明を記述しています。

### 環境

`test/unit`フォルダにはブラウザで実行される一連のテストがあり、`test/node`フォルダにはNode.jsで実行される一連のテストがあります。

ブラウザテストは["ヘッドレス" Chrome](https://developers.google.com/web/updates/2017/06/headless-karma-mocha-chai)で実行されます。これが、テストを実行してもブラウザウィンドウがポップアップしない理由です。

### セットアップとヘルパー関数

これらは現在、ブラウザテスト（ほとんどのテストがここで実行される）にのみ適用されます：

- `test/js/mocha_setup.js` は、mochaのいくつかのオプションを設定します。
- `test/js/chai_helpers.js` は、chaiをセットアップし、`chai.assert`にいくつかの便利な関数を追加します。
- `test/js/p5_helpers.js` は、p5スケッチのテストに役立ついくつかのヘルパー関数を追加します。

Node.jsテストのセットアップは、`test/mocha.opts`ファイルで完了します。

### 継続的インテグレーションテスト

p5.jsリポジトリにプルリクエストを出すと、自動的に[テストが実行](https://github.com/processing/p5.js/actions)されます。これにより、個々のコントリビュータが追加の作業をすることなく、各プルリクエストのテストが通過することを確認できます。また、カバレッジレポートは自動的に[Codecov](https://codecov.io/github/processing/p5.js)にアップロードされます。

## 単体テストの追加

より多くの単体テストを追加したい場合は、テストを追加したいコンポーネントに対するテストファイルが既に存在するかどうかを確認してください。通常、`src/`内のファイルに対応するテストファイルは、`test/unit`ディレクトリ内に同じパスで存在します。（例えば、`src/color/p5.Color.js`のテストは`test/unit/color/p5.Color.js`にあります。）

対応するファイルが見つからない場合は、そのファイルにまだテストがない可能性があります（まだ😉）、上記の規約に従って新しいファイルを作成してください。テストするモジュールがブラウザで実行する必要がある場合は、`test/unit`に配置し、そうでなければ`test/node`に追加してください。**不確かな場合は、ブラウザテストを`test/unit`に追加することを優先してください！（必要に応じて、後で簡単に他の場所に移動できます。）**

`test/unit`下にモジュールのテストファイルを追加する必要がある場合は、`test/unit/spec.js`ファイルの`spec`配列にテストするモジュールを追加してください。これにより、テストの実行時に必要なモジュールがロードされることが保証されます。`test/test.html`ファイルをブラウザで見ることによって、これらのテストを確認することができます。

### 単体テストの作成

テストする単位を選択します。それはメソッドや変数など、何でもかまいません。例として、`p5.prototype.keyIsPressed`を考えてみましょう。テストを書き始める前に、そのメソッドの期待される挙動を理解する必要があります。
**期待される挙動：** 任意のキーが押されている場合、ブール値のシステム変数はtrueになるべきです；キーが押されていない場合はfalseになるべきです。
これで、この期待される挙動に基づいて、さまざまなテストケースを考えることができます。考えられるテストケースには、以下のようなものがあります：

- 変数はブール値である。
- キーが押されている場合、trueであるべき。
- 任意のキー（文字キー、数字キー、特殊キーなど）が押されている場合、trueであるべき。
- 複数のキーが押されている場合、trueであるべき。
- キーが押されていない場合、falseであるべき。
- 他にも考えられるシナリオがあれば、それに対してもテストを書いてください！

`p5.prototype.keyIsPressed`に対するテストスイートを作成し、対応するテストを書き始めることができます。テストの整理と実行にはmochaを使用します。


```js
suite('p5.prototype.keyIsPressed', function() {
  test('keyIsPressed is a boolean', function() {
    // ここにテストを書きます
  });

  test('keyIsPressed is true on key press', function() {
    // ここにテストを書きます
  });

  test('keyIsPressed is false when no keys are pressed', function() {
    // ここにテストを書きます
  });
});
```

テストスイートの構造を構築しましたが、まだテストを書いていません。テストの記述にはchaiのassertを使用します。
例えば：

```js
test('keyIsPressed is a boolean', function() {
  assert.isBoolean(myp5.keyIsPressed); // アサート値はブール値です。
});
```

同様に、`assert.strictEqual(myp5.keyIsPressed, true)`を使用して値がtrueであることをアサートできます。chaiのassertに関する詳細は、こちらの[chaiドキュメント](https://www.chaijs.com/api/assert/)で読むことができます。
これで、テストを書き終えましたので、それらを実行して、そのメソッドが期待通りに動作するかどうかを確認してください。もし期待通りに動作しない場合は、そのためのissueを作成し、もしご希望であれば、それを修正することも試みることができます！

