VS CodeでPythonの単体テストをしてみよう

# はじめに
Visual Studio Codeにて、Python単体テストを試します。
参考にしたのは、公式のドキュメントです。

https://code.visualstudio.com/docs/python/testing

https://docs.python.org/ja/3/library/unittest.html


# unittestとは

VS CodeのPython拡張にあらかじめ組み込まれているunittestを使用しました。

まずはunittestの基本的な考え方をおさらいします。

たとえば、引数aと引数bを加算する関数があったとします。

```python
def add(a, b):
	return a+b
```

この関数に期待するのは、以下のような結果です。
（これは、関数の動作の正しさを保証するために、三通りのシナリオを用意したということですね）

* add(1,3) → 4
* add(0,0) → 0
* add(-1,3) → 2

一つ目のシナリオについて、動作を確認するためのテストコードを書いてみます。
※実際にunittestで使用するコードではないので、ご注意を。

```python
resualt = add(1,3)
if result == 4:
	print('OK')
else:
	print('NG')
```
今後、関数内部のコードを変更しても、このテストコードを走らせて正しい結果が出れば、関数が正しく動いていることを確認することができます。

そればかりでなく、さまざまなクラスやメソッドが複雑怪奇に絡み合い、コード変更の影響範囲がよくわからない場合でも、種々のテストコードにパスさえすれば、健全性が担保されます。問題が出たら出たで、大歓迎。考慮漏れを一つ潰して、コードの精度があがっていきます。

実際には、こうしたシナリオ（に基づいたテストコード）は、何十、何百と必要になってきますが、書くのも大変なら、実行するのも面倒くさいです。

そこで、テストコードを簡潔に書くことができ、ワンタッチで実行できれば、どんなにか便利なことでしょうか。

VS Codeでは、その仕組が提供されています。

# 準備

今回は、UNITTESTという名前のワークスペースを作りました。
テスト対象のファイルは、add.pyとし、コードを記入します。

```python:add.py
def add(a, b):
	return a+b
```
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55303/bf68870d-850c-c79e-5681-737d92fd798e.png">

# テスト用のフォルダを作る
ワークスペースの中に、testsというフォルダを作りました。
テストコードは、この中に格納していくことになります。
VS Codeのエクスプローラーの**「新しいフォルダ」ボタン**を使ってもいいですし、普通にファインダー（エクスプローラー）を使っても構いません。
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55303/acfe2b5a-c5e3-066a-9c4f-a0ed41f81864.png">

# テストの設定をする
ここがちょっと独特の手順となりますが、コマンドパレットを使って、セットアップします。

command + shift + p (OSX)
ctrl + shift + p (windows)

でコマンドパレットを表示させ、

```
python test
```

等と入力します。
候補として、
**Python:Configure Tests**
が、現れますので、それを選択します。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55303/1e3391b6-db23-2054-4def-08f777c027a3.png">
表示が切り替わり、次はテストの種類の選択です。
pytestも候補で提案されていますが、今はunittestをお試ししたいので、**Unittest Standard Python test framework**を選択します。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55303/efac555c-69cf-0732-f0f6-8abb0a202b23.png">
今度はテスト用のフォルダの指定です。
先ほど作成した「tests」フォルダが選択肢にありますので、それを選びましょう。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55303/fe247435-319d-78ca-f6e5-05a5318e8e18.png">

最後に、テスト用ファイルの命名ルールを選択します。このルールに従った名前を持つファイルを見つけると、VS Codeはそれをテスト用ファイルとみなしてくれます。

ここでは、標準的であろう（たぶん）**test_*.py**を選びました。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55303/6bc3f3cc-a4d5-7a83-09a6-abe00fc4deb5.png">
以上で、セットアップは完了です。
設定ファイルやフォルダが、自動的に作られています。
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55303/f974386b-4d0f-7b68-4285-90f1392307ac.png">


# テストコードを書く
testsフォルダの直下に、**test_add.py**というファイルを作成します。前段で、テスト用ファイルの命名ルールに**test_*.py**を選択しましたので、ファイル名はそれに従わなければなりません。
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55303/53c8e4d9-bdc0-6568-9efd-099033afe1e6.png">
作成したファイルに、テストコードを書いていきます。

```python:test_add.py
import unittest  # 標準モジュールを読み込みます
import add       # テスト対象のファイルを読み込みます

class TestA(unittest.TestCase):  # クラスを派生させて自分用のクラスを作ります
    def test_1(self):
        self.assertEqual(add.add(1, 2), 3)     # シナリオ1
        self.assertEqual(add.add(0, 0), 0)     # シナリオ2
        self.assertEqual(add.add(-1, -2), -3)  # シナリオ3

if __name__ == '__main__':
    unittest.main()

```
unittestの使い方としては、標準のunittest モジュールをインポートし、unittest.TestCase からテストクラスを派生させます。
まあ、僕は毎回、これをコピペです。
注目すべきは、

テスト対象のファイルをインポートしておくことと、

```python
import add
```

あとは、テストクラス内で、テストのシナリオを書いていることですね。
実際にテストをするときは、これを書き書きしていくわけです。

```python
self.assertEqual(add.add(1, 2), 3)
self.assertEqual(add.add(0, 0), 0)
self.assertEqual(add.add(-1, -2), -3)
```

**self.assertEqual(A, B)**というメソッドは、引数Aと引数Bの値が等しいことを検査するメソッドになります。

最後の記述は、テストファイル単体で実行するときに必要なものですので、今はなくてもいいですが、あっても困りません。

```python
if __name__ == '__main__':
    unittest.main()
```

さあ、テストコードを書いたら（コピペしたら）、サイドバーにあるフラスコの形をした「テスト中」アイコン（変な名前だ）をクリックして、テスト中表示に切り替えてください。
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55303/20d150cd-60f9-9291-ae74-5e00985edb2e.png">
設定した命名ルールに従ってテストファイルを作っていれば（かつテストコードに問題がなければ）、上図のように、作成したテストファイルやクラス、メソッドが表示されているはずです。

もし表示されていなければ、リロードボタンを押してください。

# テストの実行
テスト中表示にすると、ファイルやクラス、メソッドのとなりに、右向きの白三角形アイコンが表示されています。

これをクリックすると、テストが実行されます。
メソッドごと、クラスごと、ファイルごとに実行できるので、便利ですね。

サイドバーに、

**　「○個中○個のテストが成功しました（100%）」**

と表示がでれば、成功です。
![2-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55303/6f2ce4e0-1756-f5d8-c508-f2ee6dd01a31.png)
せっかくですので、テストに失敗するケースも見ておきましょうか。
三つ目のシナリオ、

```
self.assertEqual(add.add(-1, -2), -3)
```

は、-3という結果がでることを期待していますが、0を正解とするように修正しています。

```
self.assertEqual(add.add(-1, -2), 0)
```

この状態でテストを実行すると、**「0じゃなくて、-3という結果が出たぞ」**と警告してくれます。なかなか詳しいですね。
![2-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55303/9de2caa7-f98c-cbad-6b4c-a91d2c13c234.png)
ちょっと手を加えて、**assertNotEqual()**（等しくない検査）にすれば、テストにパスします。

```
self.assertNotEqual(add.add(-1, -2), 0)
```

以上で、unittestの設定は完了です！

# この先
必要最小限なことにしぼって、説明と設定を行いましたが、もちろん他にも様々な機能が準備されています。

**・数々のアサートメソッド**
作例では、値が等しいことを検査するself.assertEqualというメソッドを使いましたが、検査用メソッドは、他にもいろいろあります。

下記のアサートメソッド一覧は、参照する頻度が高いものでしょう。

[アサートメソッド一覧（Python公式）](https://docs.python.org/ja/3/library/unittest.html#assert-methods)

**・setUp()、tearDown()**
テストの実行に先立って、あらかじめ実行しておきたい処理があることがあります。
例えばCSVファイルを開いたり、DBにアクセスしたり、WEBサイトの中身を取得したり。

そんなときには、setupメソッドを使います。事後処理に使うのは、tearDownメソッドです。

[セットアップ系メソッド](https://docs.python.org/ja/3/library/unittest.html#unittest.TestCase.setUp)

**・例外処理**
例外処理を絡めたテストをしたいという需要もあるかと思います。
assertRaisesなどのメソッドを使用します。

[アサート系メソッド](https://docs.python.org/ja/3/library/unittest.html#unittest.TestCase.assertRaises)

以上です。