【Flutter】大丈夫、テストは怖くないよ

[(自分のブログ記事、大丈夫、テストは怖くないよ[技術は熱いうちに打て！]の転載です)](https://blog.dalt.me/2670)

# 概要

どうも、[@daiki1003](https://twitter.com/daiki1003)です！

テスト、怖くないですか？
面倒くさくないですか？

分かりますよ。

この記事は、そんなあなたの<strong>テストへの恐怖心を取り除く</strong>ために執筆しました。

<a href="https://blog.dalt.me/wp-content/uploads/2020/12/スクリーンショット_2020-12-30_19_44_14.jpg"><img src="https://blog.dalt.me/wp-content/uploads/2020/12/スクリーンショット_2020-12-30_19_44_14-632x450.jpg" alt="" width="632" height="450" class="aligncenter size-medium wp-image-2672" /></a>

こんなの出せたら、かっこいいですよね。
大丈夫です、この記事を読んでいただければ誰でも出せるようになります！

## 本記事の構成

・ファイルの作り方、お作法
・テストの記述
・テストの単位
・テストの実行
・coverage

大体、この様な構成で書いて行きます。
最短でテストを動かせる様になる事を最優先するため、
基本的な知識をすっ飛ばすこともあるかと思いますが、
その辺は他の記事も参考にしながら勉強してみてください。

<h2>Flutterにおけるテストファイルの作り方・お作法</h2>

さて、まずはテストファイルを作らないことには始まらないので早速作ってみましょう。

<h3>ファイルの作り方</h3>

ルート階層に存在している、<code>test</code>フォルダ以下に
テストを記述するファイルを作成します。

基本的に、どんなファイル名でどんな階層でもテストは実行出来ますが。
少しだけお作法があるので守りましょう。
後の自分や仲間を守ることになります。

<h3>ファイルを作る際のお作法</h3>

<h4>ファイル末尾を<code>_test.dart</code>にする</h4>

<code>hoge_repository.dart</code>のテストファイル名は<code>hoge_repository_test.dart</code>にしましょう。

<h4>test階層以下を<code>lib</code>階層以下と同等にする</h4>

<code>lib/hoge/repository/fuga_repository.dart</code>のテストのファイル階層は<code>test/hoge/repository/fuga_repository_test.dart</code>にしましょう。

<h2>Flutterにおけるテストの記述</h2>

さて、ファイルを作ったところで早速テストを書いてみましょう。

まず、雛形です。

```dart
import 'package:test/test.dart';

void main() {

}
```

テストファイルは必ず、<code>main</code>関数を持ちます。
この中にテストを記述していきます。

<h3>一つ一つのテストの記述</h3>

仮に、一つテストを記述してみましょう。

```dart
test('variable test', () {
  var sampleValue = 'sample';
  expect(sampleValue, 'sample');
});
```

割と直感的ですよね？

```dart
test(テスト名, () {
  // 前処理
  expect(処理や変数, 処理による結果や変数の期待値);
});
```

テストの一つ一つはこの様な書式で記述します。

<code>test</code>と言う関数を記述することで、
一つのテストを作る事が出来ます。

そして、この中に

この処理をしたらまたはこの値はこうなってほしい

と言う意味を持つ<code>expect</code>関数を0個以上記述します。
全てが「こうなってほしい」を満たすことによってテストが一つ通った (Passed) と言うことになります。

<h2>Flutterにおけるテストの単位</h2>

<h3>groupを使いこなそう</h3>

```dart
test('add test', () {
  expect(42 + 42, 84);
});

test('minus test', () {
  expect(42 - 42, 0);
}):
```

以上2つのテストがあるとします。
問題なく、通りそうですね。
これで終わりでも良いんですが、この2つ良くみてみると両方とも
<strong>整数値に対する処理</strong>を行っていますよね？

こう言う場合は、<code>group</code>関数を使ってまとめる事が出来ます。

```dart
group('integer test', () {
  test('add test', () {
    expect(42 + 42, 84);
  });
  test('minus test', () {
    expect(42 - 42, 0);
  });
});
```

記述式は<code>test</code>と一緒で第一引数に名前、第二引数に実行するテストです。

<h4>groupによるメリット？</h4>

<code>group</code>化をすることにより、実行結果を以下の様に見やすくする事が出来ます。

<a href="https://blog.dalt.me/wp-content/uploads/2020/12/image.jpg"><img src="https://blog.dalt.me/wp-content/uploads/2020/12/image-632x150.jpg" alt="" width="632" height="150" class="aligncenter size-medium wp-image-2683" /></a>

この場合、まだ数が少ないのでメリットを感じにくいかもしれませんが
数が多くなってくるとより顕著になってきます。

<h2>Flutterにおけるテストの実行</h2>

それでは、ここまで書けたところでテストを実行してみましょう。

```dart
import 'package:test/test.dart';

void main() {
  group('integer test', () {
    test('add test', () {
      expect(42 + 42, 84);
    });
    test('minus test', () {
      expect(1 / 0, double.infinity);
    });
  });
}
```

<h3>コマンドによる実行</h3>

<h4>全テスト実行</h4>

```sh
$flutter test
00:03 +2: All tests passed! 
```

<h4>指定ファイルのみの実行</h4>

```sh
$flutter test [test_file_name]
00:02 +2: All tests passed! 
```

<h4>指定したテストのみの実行</h4>

```dart
$flutter test --plain-name 'test_name' [test_file_name]
```

例えば

```sh
$flutter test --plain-name 'minus test' test/widget_test.dart
00:01 +1: All tests passed!  
```

<h2>coverage</h2>

<h3>coverageとは？</h3>

テストについて調べていると、テストカバレッジや<code>coverage</code>なんて
言葉が目に入ってくると思います。
これは、<code>全プログラムの実行フローに対してどこまでテストによって保証されているかを示す率</code>です。

ちょっと具体例を出してみましょう。

```dart
int add(int a, int b) {
  return a + b;
}
```

```dart
test('add test', () {
  expect(add(1, 2), 3);
});
```

この場合、<strong><code>coverage</code>は100%</strong>となります。

では、以下の場合はどうでしょう？

```dart
int divide(int numerator, int denominator) {
  if (denominator != 0) {
    return numerator / denominator;
  } else {
    return double.nan;
  }
}
```

```dart
test('divide test', () {
  expect(divide(4, 2), 2);
});
```

この場合、<strong><code>coverage</code>は50%</strong>となります。
なんとなく分かりましたか？
else文の方の処理を通らないので、2個のうち1つだけがテストで保証されている状態、
つまり50%となります。

<h3>coverageの出し方</h3>

では、Flutterでどうやってこの<code>coverage</code>を出すのでしょうか？

```sh
$flutter test --coverage
```

と、実行したいテストに<code>--coverage</code>を付け足してあげるだけです。

ですが、これを実行すると

<code>coverage/lcov.info</code>と言う何やら怪しいファイルが生成されるだけです。
しかも、中を見ても良く分からない...。

でも安心してください。
ここまで来ればもうちょっとで、最初に示した表が出せるのでもう一踏ん張りです！

<h3>coverageの可視化</h3>

<h4>lcovのインストール</h4>

このファイルを解析するための、ツールを一つ下記コマンドでインストールします。

```sh
$brew install lcov
```

これが終わり次第、以下を実行してみてください。

```shell
$genhtml coverage/lcov.info -o coverage/result
```

こちらが実行終わりましたら、<code>-o</code>で指定したフォルダが
生成されているはずです。

この中にある<code>index.html</code>をブラウザで表示すると
最初に示した表が表示されるはずです！

いかがでしたでしょうか？
テストへの恐怖心が少しでも減ってくれれば嬉しいです！

また、ここ分からなかったよ！とかがあれば気楽に[@daiki1003](https://twitter.com/daiki1003)まで
リプライお待ちしております！