目標
本記事では、プログラミング初心者やユニットテストをしたことがない方々に向けて、ユニットテストの概要とその導入について紹介させていただきます。
作成者自身プログラミングを始めて間も無いため、学んだことをまとめたメモ的な側面もあります。また、まだ書き途中ということもあり、論理の流れがおかしいところが多々あって読みづらいかもしれません。今後修正を加えていきます。
第一部ではユニットテストの概要をまとめ、第二部でpythonを使ってユニットテストの導入部分を説明します。
ユニットテストの概要
なぜテストをするのか
人間はミスをする生き物である。長いコードになればなるほど、そのプログラムはバグを引き起こす温床であるとも言える。
従って良いプログラムとは、コードを書かないともいえる。
現実的に開発者は、どのようなコードを書いたら、ミスがなく、第三者から見てもわかりやすくかつ、他のプロジェクトにも使いまわせる再利用可能なコードができるのだろうかなどど常に考えることとなる。
ユニットテストの登場
そこで、ユニットテストが出てくる。テストを書くことで、ミスを減らし、可読可能性の高く、再利用可能なコードを書くことができる。
実際にユニットテストを行うためには、まず関数ごとにテスト書く必要がある。そうすることで、1つの関数にいくつものテストをすることで正しさを保証することができる。また、わざわざ全体のコードを書いて初めて正しさを検証せずとも、構成要素である関数ごとに正しさを確認できる。
一方で、そのように独立な関数をいくつも作るという設計をすることである程度可読性を高められ、関数を再利用できるコードが生成される。
ユニットテストのメリット
上述のようにユニットテストは、全体の関数が正しく動作するのか調べるのではなく、関数ごとに動作をテストする手法である。ユニットテストを書くことは、全体の関数が正しいかどうかを逐一確認しながら開発を進めるため、石橋を叩いて渡ることと似ている。
ユニットテストの効能は以下の通りである。
-
ユニットテストを書くことで、開発者は、そのプログラムの正しさを検証できる。
-
あるプログラムの期待される動作の検証ができるだけでなく、第三者がテストコードを見たときに、その関数の期待される動作が大体わかる(テストコードを見れば何を計算しているのかなんとなくわかる。)
-
ユニットテストが書けるように設計してあれば、次のプロジェクトでも、前のプロジェクトで使われた関数を再利用できる。
つまり、ユニットテストを書くだけで、第三者から見てもわかりやすい、かつ後のプロジェクトでも書いた関数の再利用ができるメリットを享受できると思う。
ユニットテストの際に重要なこと
-
いかに簡単で間違いづらいテストを見つけるかが重要
-
現実的に全部の単体テスト(関数だったり、あらゆるバグの可能性に対するテスト)は無理なので、何をテストしないのかを考える。
-
テストよりも設計が大事である。 関数単位でテストができるようにコードを書いてなければそもそもユニットテストが実行できない。例えば、
例1)Aという関数でデータを作らないとBがテストできないみたいな仕様をなるべく減らす。これが10、20個あると手に負えなくなる。
例2)いかに小さい、独立した関数の集合でコードが書けるのかの設計を考える
コードのよくない例
-
引数が外部の変数に依存している場合、テストのしようがない(外部の要因に作用されるから)
-
一つの関数に数百行も書いてある。(ユニバーサルな単体関数を書くのではなく、機能ごとに分割してほしい。)
ユニットテストの導入
実際にテストを実行するとはどのようなものなのかを紹介し、テストを行うために必要なディレクトリ構造やユニットテストを行うための便利ツールを紹介する。
お手軽テスト計算を実行してみる
まずは、肩慣らしにテストを行うとはそもそもどういうことなのかをコード上で具体例で見てみる。
以下のコードはガウス求積を使ったコードの例である。
using FastGaussQuadrature
x, w = gausslegendre(3)
myfunc(x) = x**4
I = dot(w,myfunc.(x))
#テスト。x**4の[-1,1]の積分の結果に一致するはずであるのでそれを確認するコードを書く。
@assert I ≈ 2/5
これで、問題なくコードが動けば、上記のmyfunc(x)という関数の正しさを確かることができたことになる。
ユニットテストをする実行手順
ユニットテストを用いた開発を行うワークフローを以下にまとめる。
step1:jupyter notebookとかで遊んでみる
step2:関数としてまとめて、呼び出せるようにする(クラス)
step3: ソースコードとテストディレクトリをそれぞれ作り、コードを書いていく。
step4:ユニットテストを実行する。失敗すれば、step3に戻り、バグを修正。直れば、その関数のユニットテストは終了したことになる。
pythonでの例
step3から説明をする。src, testディレクトリを作る。
ここでは、簡単のため自動でユニットテストに必要なツールをインストールし、ディレクトリを自動で作成してくれるpoetryを使う。
poetryの使い方は以下を参照してください。
poetry new 〇〇で新規にディレクトリを作ると、以下のようになる。
.
├── README.rst
├── pyproject.toml
├── qiita_unittest
│ └── __init__.py
└── tests
├── __init__.py
└── test_qiita_unittest.py
2 directories, 5 files
-
qiita_unittestがsrc(ソースコードに対応)
-
testsにテストコードを書いていく。
-
__init__.py
は、おまじないみたいなもの。 -
そのほかは一旦無視してもらって良い(poetryを使って作成すると自動的にこれらは作成される。もちろん手動で作ってもらっても良い)
poetry installでpytestなどをインストールした後は、poetry run pytestでテストが実行できる。
これで最低限、開発環境が整った。後は、ご自分で作った関数とそのテストを書き込んでテストを実行していく。
なお、poetryを使用する場合、インストールするライブラリをコンパクトに収めないと、ビルドする時間がかかるので要注意かもしれない(特にDockerと併用する場合?)
GithubActionsについて
GithubActionを使用することで、Githubのサーバ上で、自動でテストが走るように設定することができる。こちらもあとで時間があればまとめる。
余談:pythonでも型チェックもできる
mypyというツールを使えば、型チェックできます。ツール導入について記事を書いてますのでよろしければご参照ください。
https://qiita.com/RhT/items/07a27a123b89cbb13e33