はじめに
この記事はZOZOテクノロジーズ #2 Advent Calendar 2019の17日目の記事となります。
昨日は @sashihara さんによる2年間チームで毎週1on1に取り組んでわかった3つの効果 でした。
今年、ZOZOテクノロジーズでは全部で5つのAdvent Calendarが公開されています。
ZOZOテクノロジーズ #1 Advent Calendar 2019
ZOZOテクノロジーズ #2 Advent Calendar 2019
ZOZOテクノロジーズ #3 Advent Calendar 2019
ZOZOテクノロジーズ #4 Advent Calendar 2019
ZOZOテクノロジーズ #5 Advent Calendar 2019
様々な記事が投稿されていますので、皆様お時間有りましたら是非ご覧ください。
本記事の目的
新卒エンジニアで入社した自分はお恥ずかしいことに、今まで単体テストと呼べるものを行ったことがありませんでした。
このままではまずいと思い、単体テストなるものにチャレンジをしてみることに。
そこで、「レガシーコード改善ガイド」という本を読んで単体テスト・テストコードの重要性を理解したので、この二点に着目してみました。
それを踏まえて自分なりに今の環境でできるVBSの単体テストをやってみたので考察を載せます。
前置き
「レガシーコード改善ガイド」によると、レガシーコードというのは、 テストで保護されていない扱いにくいコード と定義されています。
テストで保護されていない扱いにくいコード がなぜ悪いのか?(エンジニア経験のある方ならなんとなく感覚でわかると思います)
「レガシーコードからの脱却」内の言葉を借りると以下です。
レガシーコードとは、バグを多く含み、壊れやすく拡張が難しいコードを指します。
このようなコードの保守と管理には多大な労力がつぎ込まれることになります。
しかも一度作ってしまったレガシーコードの質を上げるには、初めから質の高いコードを作るよりも膨大なコストがかかります。
ざっくりと聞くだけでも課題が山積みですね。。。
「レガシーコード改善ガイド」ではそんなレガシーコードを改善する・予防するためにはテストコードが必要と述べられています。
このことからテストコードを用いて、単体テストをやってみよう!と思い立ち、実際にやってみました。
環境
自分が普段扱っている言語はVBSですが、VBSには有用なテストツールがないので自前でテストコードを書いています。
テストコードを用いた単体テスト
実践してみたテストコードの一部を抜粋。(内容は多少ぼかしてます)
これが単体テストと呼べるかも怪しいですが、、、
Call IsOverTargetAmount_test()
Sub IsOverTargetAmount_test()
Dim amount : amount = 4999
' Dim amount : amount = Empty
' Dim amount : amount = ""
' Dim amount : amount = NULL
' Dim amount : amount = "abc"
' Dim amount : amount = -7000
' Dim amount : amount = 4999.9999
response.write "amount : " & amount & "<br>"
response.write "IsOverTargetAmount : " & (IsOverTargetAmount(amount) = False) & "<br>"
End Sub
Function IsOverTargetAmount(ByVal amount)
IsOverTargetAmount = False
If Not (IsNumeric(amount) And amount <> "") Then
' 引数が数値かどうかバリデーション
Exit Function
End If
If amount >= 5000 Then
IsOverTargetAmount = True
End If
End Function
' ▼実行結果
' amount : 4999
' IsOverTargetAmount : True
単体テストにチャレンジしてみての考察
- 可能な限り、I/Oがシンプルなものにする
- I/Oが複雑なものはテストコードが書きづらく、レガシーコードになりやすい
- 最低限Iは複雑でも、Oはシンプルだとテストが楽(個人的理想はBool値)
- バリデーションは以下の値に注意する
- 変数の型(数値なのか、文字列なのか、オブジェクトなのか)
- 数値の場合、少数や負の整数、型の限界値(INTなら -32,768 ~ 32,767)、境界値(不等号の周辺値)
- 空文字、Empty、NULL、Nothing 等の特定のイレギュラーになりうる値
- テストコードはあくまで書いてあるコードが正しいことを確認する
- 仕様(ビジネスロジック)が正しいかどうかはテストコードでは確認できない
- DB側は単体テストが難しい、、、
- DBとの接続が発生する場合、モック的なテストデータが必要
- 準備が手間
- 手戻りが手前になる
- 結合テストフェーズになって、手戻りが発生すると厄介なのでそれを防げる
- そもそも他と依存関係のないコードでなければ単体テストとは呼べない(単体テストをするのが難しい)
- 単体テストにはホワイトボックス・ブラックボックステストがある
- Ref : 単体テスト(ユニットテスト)とは
- ホワイトボックスではコードが正しいことを確認する
- ホワイトボックステストのカバレッジについてはこちらを参考に
- Ref : ホワイトボックステストにおけるカバレッジ(C0/C1/C2/MCC)について
- ブラックボックステストでは仕様が正しいことを確認する
- 仕様の確認なので人の目によるレビュー等が必要
最後に
今回テストコードを書いて単体テスト(ホワイトボックステスト)を行ってみた感想としては、少なくともやる意味はあると思いました。
後戻りする機会が圧倒的に減ることメリット、主観的に完成度は上がると感じました。
しかし、プログラムの書き方や言語によってテストのハードルはかなり差が生まれるというのも実感しました。
単体テストの自動化できる言語もある中、自分でテストコードを書くのは正直工数が増える面があると思います。
また、テストのエビデンスの残し方やテストコードの管理方法等も考えなくてはなりません。
まだまだ課題は山積みですが、今後のサービスの成長に合わせて、微力ながらレガシーコード改善に取り組めればと思います。
(ただ、レガシーコードでもサービスとしてここまで成長できたことは非常に尊敬しています。)
明日は @mitanih さんが記事を書きます!ぜひご覧ください!