この記事は以下のターゲットを対象としています。
★5 Django の開発経験が 3 年以上。
★4 Django の開発経験が 1 年以上。
★3 WEB サイト開発経験あり。これから Django を学習します。
★2 Python 初級者。簡単なプログラムコードが書けます。
★1 プログラミング未経験。
Djangoバージョンアップにおけるテストコードについて
こんにちは、グローバルウェイの有浦です。
前回Djangoバージョンアップの作業についてご紹介しました。
本稿ではDjangoバージョンアップにおけるテストコードの役割とテストコードの書き方について記載いたします。
また本稿において、pythonのテストコードであるpytestとその結果を出力するカバレッジレポートについても紹介いたします。
なぜテストコードが必要か
テストコードは、前回ご紹介しましたロードマップの「⑤全体リグレッションテスト」に関連してきます。
「⑤全体リグレッションテスト」は以下のような役割をもつと紹介をさせていただきました。
[各工程の作業概要] ⑤全体リグレッションテスト 修正箇所以外の機能についても正常系ワンパスを通して動作確認を行います。 |
上記の説明ですと、修正箇所のみを試験すれば、Djangoバージョンアップの改修分については、動作確認的に問題ないと思われます。
しかし、実際にはリリースノートにかかれた変更点のみを試験するのでは、不十分だと感じる重要な機能があることと思います。
そこでテストコードを使用することで、網羅的に機能の試験を行うことができます。
テストコードとは何か
そもそもテストコードとはどのようなものかについてですが、開発したプログラムの処理が期待通りに動くかを確認するための専用のソースコードとなります。
テストコードを使用するメリットとして、ソースコード上での動作確認となるため、ブラウザからの手動試験と異なり、作業者のアプリケーションの理解度にかかわらず同じ試験結果が期待できること、また一度作成しておけば、試験の工数がテストコードを実行するだけで済むため、再試験の工数が大幅に抑えられることなどがあげられます。
逆にデメリットとして、テストコードを作成するコストがかかること、システムの機能拡充に応じたテストコードの修正など、ランニングコストがかかることが挙げられます。
導入メリット | 導入デメリット |
作業者のレベルに関係なく動作確認が可能。2回目以降の実施のコストが抑えられる。 | 作成コストがかかる (おおよそ開発と同じくらい)更新が頻繁なシステムの場合、その更新に合わせた修正ランニングコストがかかる |
テストコードの基本
テストコード開発は以下の順に実施します。
- 機能のユースケースを書き出す
- ユースケースを基にテストコードを開発する。
本記事ではテトコードを作成するにあたり、カバレッジ(※)を100%にするためのテストコードを開発するのではなく、機能のユースケースを満たすテストコード開発を行うことを念頭に置いた記事となっております。
※カバレッジ(Coverage)とは テストコードを動かしたとき、テスト対象のコードがどの程度網羅されているかのパーセントです。コードのすべての処理を通ると100%となります。 カバレッジにも種類があり、命令網羅C0、分岐網羅C1、条件網羅C2、複合条件網羅MCCの種類があります。 なぜカバレッジ100%を目指さないのか、上の4種類が何なのかについては別の機会に紹介できればと思います。 |
pytestの導入方法
ここからは実際のpythonにおけるpytestの導入方法とその使い方について、説明していきたいと思います。
pytestはPythonでのテストコードを簡単に実装できるフレームワークとなります。
ご自身の環境で以下のコマンドをたたくことで、簡単に導入が可能です。
$ pip install pytest |
上記インストールが完了しましたら、pytestのライブラリを使用する準備は完了となります。
ユースケースの作成
まずはテストコードを作成する前にユースケースの洗い出しが必要です。
ユースケースを作成するには、設計書や仕様書、UMLなどから対象の機能がどのようなユースケースかを考え作成します。
例えば、DBからデータを取得し一覧を表示、検索が可能な画面のユースケースだった場合以下のようなケースが考えられます。
【一覧画面表示で考えられるユースケース例】 ① 初期表示 ② 遷移先から戻る ③ 検索ボタン、検索条件なし、検索結果あり、次画面遷移 ④ 検索ボタン、検索条件あり、検索結果あり、次画面遷移 ⑤ 検索ボタン、検索条件あり、検索結果なし ⑥ 検索ボタン、異常系(不正な値での検索) など |
ユースケースが完成したら、次はいよいよテストコードの実装になります。
テストコードの作成
テストコードの簡単な例を挙げると以下のようになります。
# test_sample.py def inc(x): # intに1を足して返却する関数 return x + 1 def test_answer(): # ユースケースに相当 # assertで左辺にコードの結果を、右辺に期待値を記載します。 assert inc(3) == 5 |
上記のテストコードを実行すると、失敗が返ってきます。
assertで失敗していることが上記のコンソールからわかります。
4==5ではないため、テストコードは失敗を返却しています。
このようにassertを使用することで、関数が期待通りの結果を返却できているかを評価することができます。
もう少し先ほどのテストコードを実務向けに書き足すと、
# test_sample.py def inc(x): # intに1を足して返却する関数 return x + 1 def get_mock_list(): # テスト用のレスポンスモック __response_mock = {“status_code”: 200, “url”: “/get_list”, “form”: {“target_id”: 10, “condition”: “id”}, “template_name”: “web/test_list.html”} return __response_mock def test_answer(): assert inc(3) == 5 def test_正常系初期表示(): __response = get_mock_list() assert __response[“status_code”] == 200 assert __response[“url”] == “/get_list” assert __response[“form”][“target_id”] == 10 assert __response[“form”][“condition”] == “id” assert __response[“template_name”] == “web/test_list.html” |
実行結果は以下のようになります。
1passedが増えていることがわかります。
これはすべてのassertを期待値通りに通過していることを示しています。
上記ではpython上にmock用の定数を用意し、それを評価させていますが、__response_mockの部分をformの初期化に置き換えたりすることで、formの初期化がdjangoのバージョンアップ前後で同じformの構造を返しているかテストコードを動かすことで確認が可能です。
またテストコードでは関数名を日本語にすることで、そのテスト関数がどのユースケースを示しているのかわかりやすくなるメリットがあります。
実行結果の出力(カバレッジレポート)
プロジェクトでは、成果物としてテストを実施した証跡が必要となることがあると思います。そこで役に立つのがカバレッジレポートです。
カバレッジはテスト実行の網羅率のことです。
このカバレッジを出力したカバレッジレポートはpytest-covというライブラリを使用することで出力することができます。
導入方法は先ほどのpytestと同じくpipコマンドでインストールします。
$ pip install pytest-cov |
インストールが完了したら早速実行してみましょう。
$ pytest -v –cov={実行するディレクトリ} |
実行結果は以下
カバレッジの出力項目が増えていることがわかります。
この結果はあくまでもコンソールのため、視認性をあげるためにレポートをhtml出力することも可能です。
以下を実行することで上記のコマンドで生成された”.covarage”のファイルを基にhtmlを作成することができます。
$ coverage html Wrote HTML report to htmlcov\index.html |
※covarageのライブラリはpytest-covをinstallしたタイミングでインストールされているため、個別でのインストールは不要となります。
実行後ディレクトリを確認するとhtmlcovのフォルダが生成されていることがわかります。
index.htmlをブラウザで確認すると、各pythonのテストコードの実行結果が一覧で表示されます。
先ほどtest_sample.pyをクリックし中身を確認すると次の画像のようになります。
緑色の部分はテストコード実行時に“通過”した場所となります。
全ての行が緑のため、このテストコードはcoverage100%であることがわかります。
まとめ
今回はテストコードとカバレッジレポートについて触れさせていただきました。
テストコードは開発コストがかかりますが、関数やクラスへの理解が深まるという学習的なメリットや、単純な手動試験を実施しなくて済むようになる(=他の作業に工数を割ける)作業的なメリットもあります。Djangoバージョンアップの際に使用すれば、全機能の網羅的な試験の工数を大幅に削減可能です。
機会があれば是非挑戦していただければと思います。