新人に伝えたい、単体テストの考え方について

こんにちは
エンジニアリングソリューション事業部のKです。
今回は単体テストについて語っていきます!
※プログラミングコードは一切つかわない記事になります。

単体テストって結局何するの?

プログラミング初心者や、研修を受けている方で単体テスト、結合テストという言葉を聞いて
「具体的に何をするんだ」「具体的にどう違うんだ」とつまづいたことはありませんか?
私も初めて聞いた時はよくわからなかったし、実際の仕事で見たテストコードは何をテストしたいのか
理解することができませんでした。

なので、なるべくわかりやすく伝えられるように身近なものにたとえて単体テストの考え方について
説明したいと思います。

自動販売機の機能をテストしてみましょう

今回は自動販売機の機能をテストするという形で説明していきます!
まずは、自動販売機に欠陥がないか確認して下さいと言われた時に
何も聞かずどんなことを確認するかイメージしてください。
自動販売機写真

①1000円入れて150円のコーラを選んだらコーラと850円のお釣りがでてくるんだろうな
②50円だけいれて150円のコーラを選んでも何も出てこないんだろうな
などと思い浮かべませんでしたか?


実はそれは結合テストの考え方です。
検証の起点となる部分を決めて、複数の機能の処理結果を受けて最終的に出力される結果が
正しいかどうかを確認することが結合テストで
上記①、②のようなテスト内容の分け方はシナリオケースと呼ばれます。

それでは単体テストでは具体的にどんなことを確認するのでしょうか?

自動販売機が持つ機能について

本題に入る前にまずは前提となる自動販売機の細かい仕組みについて説明させてください。
自販機は大きく分けて3つの機能があります。
①商品の在庫表を持ち、実物を保管する倉庫となる機能
②商品のサンプルを見せる機能
③選択された商品と投入されたお金を計算して、商品とお釣りを返す機能

上記の3機能が自動販売機を構成する最小単位の機能とすると
それぞれの機能に欠陥がないことを確認するのが単体テストとなります。

単体テストで検証すること

それでは、それぞれでの機能ではどんなことをテストすれば良いでしょうか?
順番に確認していきましょう。

①商品の在庫表を持ち、実物を保管する倉庫となる機能

こちらはシンプルで
・在庫をきかれたら在庫表を渡すこと
・「〇〇(コーラ等)』を持ってきてと指令を出されたらその商品を持ってくること
です。

②商品のサンプルを見せる機能

この機能のテスト内容は何でしょうか?
『コーラ』『サイダー』『お茶」がメニューに並んでいることでしょうか?

どの自動販売機もそのラインナップとはかぎりません。
在庫を把握しているのは”①商品の在庫表を持ち、実物を保管する倉庫となる機能”のみなので
この機能に在庫数を尋ねる必要があります。

この場合では
・①機能に在庫数、ラインナップを尋ねること
・①の機能からきた在庫数、ラインナップをそのまま表示すること
です。
※ただし在庫がない場合、購入者に在庫がないことを伝える必要があるので
・①の機能からきた在庫数、ラインナップを売り切れとして表示すること
と検証内容が変わってくることがあります。

③選択された商品と投入されたお金を計算して、商品とお釣りを返す機能

選択された商品が『コーラ』だったとしましょう。

投入金額≧商品代金、の場合
・”①商品の在庫表を持ち、実物を保管する倉庫となる機能”に『コーラ』を持ってくるように指令を出すこと
・計算したお釣りと”①商品の在庫表を持ち、実物を保管する倉庫となる機能”が持ってきた商品をそのまま返すこと。

投入金額<商品代金、の場合
・”①商品の在庫表を持ち、実物を保管する倉庫となる機能”に指令を出さないこと
・投入された金額をお釣りとしてそのまま返すこと
となります。
ここは選択された商品と投入された金額によって検証内容が異なってくるので注意が必要です。

以上が主にそれぞれの機能をテストするときの内容です。

結合テストと単体テストがごっちゃになってしまう部分

例えばですが
③選択された商品と投入されたお金を計算して、商品とお釣りを返す機能” をテストしたいとき

1000円を投入して『150円のコーラ』を選択したときコーラと850円のお釣りを返すこと

といったテストケースを考えたりしていませんか?
一見問題なさそうなテストケースに見えますが、もしそのテストの結果が

1000円を投入して『150円のコーラ』を選択したとき『サイダー』と850円のお釣りが返ってきた

だった場合は、③機能には欠陥があるため原因を探さないと!となると思います。
おそらく原因は以下のようなものが考えれるでしょう。
A”①商品の在庫表を持ち、実物を保管する倉庫となる機能”に『サイダー』を持ってきてと依頼を出していた。
B”①商品の在庫表を持ち、実物を保管する倉庫となる機能”が『サイダー』を持ってきてしまっていた。

よく見るとAは ③の機能の欠陥ですがBは①の欠陥です。
1000円を投入して『150円のコーラ』を選択したとき という箇所は①の機能が処理するところのため、このテストケースだと2つの機能を同時に検証していることになります。
これだとまずどちらの機能が問題なのかを調べる必要が出てくるので調査に時間が取られてしまいますね。

本来、③の機能で確認したいことは
・”①商品の在庫表を持ち、実物を保管する倉庫となる機能”の機能に『コーラ』を持ってくるように指令を出していること
・計算したお釣りと”①商品の在庫表を、持ち実物を保管する倉庫となる機能”が持ってきた商品をそのまま返すこと。
ということです。

もし、 ③の機能が上記のような観点でしっかり担保できていれば
”①商品を在庫表を持ち実物を保管する倉庫となる機能”が『サイダー』を持ってきてしまっていた。
という原因に早く気付くことができるようになります。

単体テスト、結合テストで確認すべき点

このように、一機能の検証で他機能の結果の内容まで検証してしまうと
どの機能で不具合が発生したか特定が困難になってしまいます。

そのため単体テストでは

一機能の入力値が正確か確認する。(1000円が投入され『コーラ』が選択されている)
一機能が他機能を正しく利用している。(”①商品の在庫表を持ち、実物を保管する倉庫となる機能”に
『コーラ』を持ってくるように指令を出している)
・使用した他機能が出力した内容を正しく利用している。(”①商品の在庫表を持ち、実物を保管する倉庫となる機能”が
持ってきた商品をそのまま出力する。)
※(”③選択された商品と投入されたお金を計算して、商品とお釣りを返す機能”の検証例)

を検証ポイントとし、対して結合テストでは

・複数の機能が相互的に作用した結果最終的に正しい出力を行なっている。(1000円を投入し『コーラ』を選択すると
取り出し口に『コーラ』と850円が出てくる。)

を検証ポイントとすることが必要です。

まとめ

さて、「結合テスト」、「単体テスト」についての違いのイメージがついたでしょうか?
単体テストを実施する際には結合テストになってしまわないように是非このポイントを意識してみてください!

投稿者: エムシバ君