nobu blog

プログラミングやゲームの話など。

*



【技術書感想】JUnit実践入門はJava技術者以外でもユニットテストを実装する技術者が読むべき入門書

      2021/10/13

概要

JUnit実践入門を読んだので簡単に内容をまとめようと思います。
Javaを使ったJUnitの本ですが、Java以外の静的型付言語で使われているxUnit系のテストに関しても有用な本となっています。

(2021/10 追記)
下記の記事で似たようなテーマを扱う実践JUnitを紹介していますので合わせてご覧ください。

【オライリー本感想】実践JUnitは読みやすく、体型的にxUnitを使用したユニットテスト方法が学べる良書

本書では,JavaテスティングフレームワークのデファクトスタンダードであるJUnitの基本的な使い方から,拡張機能,テストパターンまでを網羅的に解説します。

スポンサーリンク

書籍概要

どんな本?

本書では,JavaテスティングフレームワークのデファクトスタンダードであるJUnitの基本的な使い方から,拡張機能,テストパターンまでを網羅的に解説します。また,データベースやAndroidのテストを取り上げるほか,ユニットテストを開発に効果的に取り入れるためのビルド支援ツール・カバレッジ測定ツール・継続的インテグレーション・テスト駆動開発などの周辺技術について,ユニットテストからの視点で説明します。JUnitをこれから学びたい方,もっと効率的にユニットテストしたい方,必読の書です。

  • 渡辺修司 著
  • 2012年11月21日 発行
  • 480ページ
  • 定価3,630円(税込)

スポンサーリンク

内容のまとめと感想

Javaのユニットテストフレームワークである、JUnitをテーマにユニットテストの話を網羅的に解説している書籍です。

テストの手法や意味といった思想から、JUnitを使ったテストコードの書き方、テスト駆動開発までユニットテストに関係する内容が網羅的に記載されているので、網羅的に学習する事ができます。
コードも豊富にありユニットテストを書いた事が無いというエンジニアであれば、どういったものなのかを学ぶのには最適な本だと思います。

JUnit自体は、その他の言語に存在するユニットテストフレームワークと同じような思想で作られているので、静的型付言語のユニットテストフレームワークを使っているという人にも参考になると思います。
(私自体もJavaには疎く、C#のユニットテストに関する知見を得るために本書を読みました。)

480ページとかなりボリュームがありますが、文章が読みやすく意外とあっさり読む事ができます。

網羅的に説明しているので、ある程度の経験があるエンジニアだと知っているよ的な内容も多いのですが、私個人としては復習といった観点で読む事ができました。
テストの対しての考え方や方針などの説明も多く、どういったテストコードを書いたら良いのかといった点を学ぶのにも良いと思います。

個人的にはもう少し複雑なケースにおけるテストコードやリファクタリング等の内容が読みたかったので、その点は物足りませんでした。
ただ、言語やフレームワークやユースケースで様々なパターンが考えられるのでそれらを全てカバーするテスト手法を書き出すといったことは難しいのかもしれませんね。

本書では,JavaテスティングフレームワークのデファクトスタンダードであるJUnitの基本的な使い方から,拡張機能,テストパターンまでを網羅的に解説します。

オライリーから出ているこちらの本も気になっているので、読んでみたいと思っています。
タイトルからしてより実践的な内容なのでしょうか?

Javaユニットテストのデファクトスタンダード「JUnit」の解説書。

スポンサーリンク

読書ノート(個人的なまとめ)

第1章 JUniチュートリアル

JUnitの環境設定を含めた導入が中心となっています。
なぜユニットテストを行うのか?から始まり、簡単な計算クラスを例にJUnitを使ったテストコードの実装までが紹介されています。
経験者などはサクッと読んでしまえば良い章ですね。

  • ユニットテストをする理由
    • プログラマが自分の書いたコードに責任を持つため
    • 不安を無くすため
    • ユニットテストは万能ではなく、クラスやメソッドの相互作用の品質は確保できない(=>機能テストや受け入れテストの役割)
  • 企業文化とユニットテスト
    • ユニットテスト(単体テスト)という単語の定義は企業によって異なる
    • A社は画面系の単体機能のテスト、B社はJUnitによるテストなど。

第2章 ユニットテスト(何のためにテストするのか?)

一般的なテストやユニットテストに関する知識や考え方をまとめている章になります。

目的や、テスト技法(ホワイトボックス、ブラックボックス、同値グループ、境界値)など、テストをある程度経験した事がある人ならば知っていると思われる内容が多いので、サラッと読んで復習するといった事もできるかと思います。

  • ソフトウェアテストの目的
    • 品質保証以外の目的として、設計そのものの妥当性を検証する目的もある
    • UnitTest自体は品質を高める事が直接の目的ではない
    • 対象のクラスやメソッドの動きを仕様として明確化して保証する事が本当の目的
    • その結果として品質が向上する(素早いフィードバックと自動化による副次効果)
  • テスト技法
    • UnitTestはホワイトボックステストに分類されるテストだが、内部構造を意識しすぎたテストは脆くなるので、外部仕様を意識したブラックボックス的な観点も必要(両方の観点が必要)
  • 有益なテストパターン
    • 仕様書として読めるテスト(クラスやメソッドの振る舞いに対してのサンプルコードとしてあるべき)
    • 問題の局所化(失敗時に原因特定が容易なようにテストケースは小さくする)

第3章 テスティングフレームワーク

JUnitを使って実際のテストコードの書き方と、良いテストコードを書くためのガイドラインが書かれている賞です。
JUnitを使った説明ですが、xUnit系のテストであれば同じような概念のものが殆どなので書き方の参考になると思います。
この章もxUnitを書いた事があるエンジニアであれば、知っている事が多いので見直し程度で読むのが良いと思います。

  • テストしやすいメソッド
    • 戻り値がある
    • 副作用がない(内部状態が変更されない)
    • 同じ状態、パラメータで実行したら同じ結果となる

第4章 アサーション

JUnitに提供されているアサーションに関してまとめられている章です。
JUnitにはMatcherAPIという仕組みが途中から導入されていて、より宣言的で可読性の高いアサーションが書けるようになっています。

今回はJUnitでのテストを書く事が目的で読んでいなかったので、直接参考にはなりませんでしたが、昔からあるレガシーな書き方意外にもこういった書き方があるんだなぁと参考になりました。

第5章 テストランナー

JUnitをIDEから動かさずにCUIから動かす方法に関して書かれています。
付随してCUIで動かす際にテストコードに付与すると有効なアノテーションなどが書かれています。

CD/CIに組み込む際には役立ちそうですが、ユニットテストの書き方を学びたいという人はこの章はサラっと読むだけで良さそうです。

第6章 テストコンテキスト

共通的なテストのグループ化など、テストコードの可読性を上げるためのテストの構造化に関して説明されている章です。
JUnit以外で使用できるのかわかりませんが、ネストしたクラスを使用した構造化に関しては便利だなぁと感じました。

  • テストクラスの構造化
    • 一般的にテスト対象のクラスごとにテストクラスを作成して整理する
    • ただし、大規模になるとこれでは可読性が下がり、読みにくくなる傾向(全てが同列にあるから)
    • 何らかの基準でグループ化とテストクラスの構造化が必要
  • テストケースのグループ化
    • ユースケース毎にテストクラス内にさらにネストしたテストクラスを作る(例:データが空の場合、データがX件の場合)
    • BeforeやAfterといったクラス共通のセットアップ処理が分離されて読みやすくなる

第7章 テストフィクスチャ

テストにおける前提条件の作成にフォーカスした章です。
クラスやデータのセットアップをどのように実施するか?といった方法が説明されています。
このあたりの機能はxUnitであればだいたい実装されているのでJUnitでなくても、そのパターンを学ぶのには最適だと思います。

第8章 パラメータ化テスト

テストを行う上で必要になる、入力値、期待値のパターンをどのようにテストに入れるべきか?に関して書かれた章です。

前半は、2章にも話のあった一般的なテスト手法(境界値、同値グループ)を使用してどのようにテストケースを用意すべきかが説明されています。
後半は、そのテストパターンをJUnit上でどのように冗長にならずに書けるかといった点を説明しています。

テストパターンをユニットテストケースに流し込む方法は方法は違えど、xUnitには用意されている機能なので、前半を中心に読み込むと参考になるかもしれませんね。

  • パラメータ化テストの問題
    • 網羅性はテスト設計者に依存する。技法を学び、レビューをする事が必要
    • パラメータによる情報の欠落(どのパラメータで失敗したかわりにくい) => アサーションの失敗メッセージにパラメータを入れておくとわかりやすくなる

第9章 ルール

JUnit独自の機能であるRuleに関してまとめている章です。
JUnitでは共通的な機能はテストクラスの継承で作るのではなく、Ruleとして切り出して利用するという作法なので、各種共通的な機能に関して組み込み機能と自分で拡張する方法が説明されています。
JUnitを使う必要がない人はこの章はサラッと読んでしまってよいと思います。

第10章 カテゴリ化テスト

UnitTestが多くなると問題となるスローダウン問題(テスト実行に時間がかかる)に関して、どのように対策していけば良いかに関して説明されている章です。

後半は、スローダウン問題事態への対処として、タイトルにもなっているテストのカテゴリ化によるグルーピング手法に関して書かれています。

  • スローテスト問題への対策
    • テスト実行時間を短くする(チューニング) => 根本的な解決になるがリスクが高い
    • テスト実行環境の強化(実行マシンのスペックアップ) => リスクも低く効果的
    • テストの並列実行 => テストが独立していないと実現不可。分割方法の考慮が必要
    • テストの絞り込み(目的に応じたテストのグループ化) => カテゴリ機能で実現できる
  • カテゴリ化のパターン
    • データベーステスト
    • デ通信処理のテスト
    • GUIを伴うテスト

第11章 テストダブル

UnitTestにおいて依存関係を切り離してテストを行うために定番となる、スタブとモックに関して書かれている章です。
このスタブとモックを合わせてテストダブルと呼ぶようです。

JUnitを使った実際のコードを使ってモックとスタブを使用したコードが書かれているので、どういったものなのかイメージが掴みやすいと思います。

  • スタブとは?
    • 依存オブジェクトのふるまいをテスト用に差し替える方法
    • 依存オブジェクトのメソッドの戻り値などを想定される値を返すようにする
  • モックとは?
    • 依存オブジェクトの呼び出しを差し替える方法
    • 依存オブジェクトのメソッドが想定された引数等で呼び出されているかアサーションする
  • スパイとは?
    • 依存オブジェクトが副作用(状態変更)がある場合に、依存オブジェクトの内部情報をラップして保持するクラス
    • スパイオブジェクトを使用する事で内部状態がアサーションできる。ロガーなどに対して使用する

第12章 データベースのテスト

一般的なUnitTestでは、DBへのアクセスする処理はモックやスタブによって実際にアクセスしないように処理を差し替えますが、本章では実際にDBにアクセスしたUnitTestの手法が紹介されています。

JUnit特有のライブラリやツールを使った説明にが主になりますが、こういったものなのかといった雰囲気を掴んで別の言語やフレームワークでも考え方を参考にすることはできると思います。

  • DBを使ったテストのメリットとデメリット
    • メリット:DBを使用しないと発見できない問題を見つけられる
    • デメリット:処理時間がかかる。DBの開発責任が分離していない環境では大変。

第13章 Androidのテスト

この章は、これまでとうって変わってAndroidに特化して書かれた章です。
現在はAndroidといえば、Kotlinを使うと思いますが結構古めの本なのでJava時代のAndroidアプリを想定したテストコード紹介されています。

基本的にAndroidに知見がなければスルーしても良いと思いますが、画面のあるアプリケーションにおけるUnitTestとはといった観点でも説明などが行われているので、その点は参考になるかもしれません。

第14章 コードカバレッジ

UnitTestにおける実行網羅率を示す、コードカバレッジに関して解説がされている章です。

Unitにおけるカバレッジの計測を行うためのツールとその使い方がメインとはなっていますが、それだけではなく、
C0~C2といった一般的なカバレッジに関する概念や説明、コードカバレッジの意義などJUnitに限らずUnitTestにおけるカバレッジの考え方を学ぶには良い章です。

よく言われている事ですが、コードカバレッジ自体を目的にする事は意味がないという事がはっきりと書かれていて、改めて自分の頭を整理する事ができました。

  • カバレッジ測定の効果
    • 実行割合を示す指標でしかないが、ユニットテストを進める上で役立つ情報を得られる
    • 問題発見のきっかけ:極端に低いクラス、テストを追加したのに変化がないなら意図した動きをしていない など
  • カバレッジとは何か?
    • 実行割合を示す指標でしかないので、処理の実装漏れや仕様の誤りは検出できない
    • なので、100%のカバレッジは品質や仕様の妥当性は保証しているわけではない => 高カバレッジを目的にすることはNG
    • 十分に良いテストが行われているならば指標として効果があるが、いい加減なテストが含まれていれば意味はない
  • カバレッジの目標はどれくらいとするべき?
    • 普遍的な答えはない。一般的に80-90%程度を目標とするプロジェクトが多い。
    • テスト戦略や予算、対象するパッケージ(テストしやすい、しにくい)で設定するのが望ましい

第15章 継続的テスト

UnitTestを継続的インテグレーション(CD/CI)に組み込むための手法や考え方が説明されている章です。

CD/CIを実現する上で必要となる各種ツール(構成管理ツール(SVN,Git)、Jenkins)なども説明されています。
CD/CIに馴染みが無い人は、この章を通してどうやってUnitTestを組み込めば良いのが学ぶ事ができそうです。

Javaに詳しく無いのですが、ビルドツールとしてはMavenが使われていて時代を感じますね。
この辺りはJUnit使っていても参考にならないかも。

第16章 テスト駆動開発

昨今は耳にする機会も増えてきた、テスト駆動開発(TDD)を取り上げた章です。
実際のサンプルコードを使ってどういったものか、示すと共に、テスト駆動開発のメリットに関して端的に説明がされています。

詳細を学ぶには、テスト駆動開発の本があるのでそれをしっかりと読むと良いと思いますが、さわりとしてどういったものかを知るには良い粒度だと思います。

  • テスト駆動開発の目的
    • プログラマの不安を軽減すること
  • なぜ不安が低減されるのか?
    • 1回のサイクルで小さいものをひとつずつ作るのでミスを大幅に減らせる
    • 自分が最初に使う(テストする)ので、ユーザビリティの高い実装になる
    • 動作するリファクタリングされた綺麗なコードになる
    • CD/CIによる素早いフィードバック
    • テストケースが第一にあるので、動作するサンプルコードとドキュメントとなる

第17章 振舞駆動開発

UnitTestではカバーできない、システムとしての振る舞いをチェックするシステムテストを自動化するためのツールであるCucumberを使用して、ユースケースからコードを開発していくという手法を紹介している章です。

以前紹介したオライリーのSelenium本でもCucumberの話が出てきましたが、今回はJUnitに統合した場合の使用例になっています。
サンプルとしてポーカーゲームを例にして、実装を行っていますが、正直ピンときませんでした。

というのもクラスやメソッドに依存せず、実際のユースケースに沿ってケースを想定して実行するテストにおいて、JUnitの延長でクラスを操作してテストを行っているからです。

GUIを使ったSeleniumのような、実際のシステムの操作を想定したユースケースを考えた方が良かったのではと思いました。
(画面があるようなシステムでこういった、クラスベースのJUnitを使ったテストを実装できるのかは疑問)

  • 受け入れテストの自動化
    • リグレッションの防止と早いフィードバックを実現できる
  • 振舞駆動開発と受け入れテスト
    • どのような仕様が想定されるかを記載し、シナリオを作る

第18~20章 演習問題

これまで学んだ内容を確認するための各種問題があります。
仕様が書かれていてそれをテストするためのコードを書くという流れは面白いです。

テスタビリティの高いコードを書くために、リファクタリングをするといったような例題もあるともっと面白くなったのではと思いました。

 - 技術書, 読書感想