この記事は東京高専プロコンゼミアドベントカレンダー②16日目の記事です。①の10日目の記事をまだ書いていない気がしますがきっと気の所為です、ええ。
Djangoでtestsを書いてみたので記事にします。
モチベーション
去年のadvent calendarのネタとして作ったto2.pwをまだ動かしているのですがバグを直したり機能を追加するたびに全ての機能が問題なく動くか確認するという作業が発生して実際何度かインシデントを起こしたりしたのと、自分がメインの開発でテストコードを書くという経験をしたことがなかったので書いてみました。決してadvent calendarのための記事を書かないといけないからではない
記事中で出てくるコードは大体ここにあるので全体が見たかったらどうぞ。
testsとは?
ここで言うtestsはソフトウェアテストのことです、ソースコード本体とは別にソースコードを”テスト”するためのコードを書き、自動で実行してバグの発生を防ぎます。最近では(?)ソースコード本体を書く前に仕様として満たすべき内容のテストを書き、その後開発するTDD(Test-Driven Development, テスト駆動開発)なる概念もあったりします。
日本語でtestsと”s”を付けて書いたら学校の定期テストなどではなくソフトウェアの自動テストを指すことが多い気がします、Googleも”tests”を”ソフトウェアテスト”と認識してるっぽいです。
Django
Pythonで書けるweb frameworkです、全てのweb frameworkの中で一番高機能(or 高レイヤー)な気がします。初めから管理画面がユーザー認証が用意されていたりします。去年の課題部門ではDjangoを使った開発をしていたはずです、あと最近は使われてませんが(そもそも物をおいてないですが) 部内のpossysもDjangoを使って書かれてます。
ちなみにDjangoは”ジャンゴ”と発音します、ディジャンゴとか発音すると大変恥ずかしいので気をつけましょう。。
Djangoでunit testを書く
正直Djangoのドキュメントぐう有能なのでドキュメントを参照してほしいんですが、なんとなくこんなことができるよ的なノリで参考程度にtestsの書き方を書いていきます。
パス
.
├── manage.py
└── app
├── init.py
├── admin.py
├── apps.py
├── migrations
├── models.py
├── tests.py
├── urls.py
└── views.py
Djangoでプロジェクトを作ったらだいたいこんな感じだと思いますが、tests.pyにテストを書き込んでいく、もしくは tests ディレクトリを作ってその中に test_hogehoge.pyを作っていくのが一般的っぽいです。ただ実行されるファイルはプロジェクト内のtest*.pyなのでそれさえ満たしてればなんでも良さそう。
実行
実行は
python3 manage.py test
で行います結果は
“`
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..
----------------------------------------------------------------------
Ran 5 tests in 0.083s
OK
Destroying test database for alias 'default'...
みたいな感じで帰ってきます。
書き方
下の例では割り算をする関数
のテストコードを書いています。division
test_zero_division
は0除算をしたとき-1を返すという
の仕様をテストしています。division
test_division
は割り算が正しく行われるか調べています。asertEqual(a,b)
というのはa=bのときテストが成功したと判断します。逆にa!=bだった場合テストに失敗したことを知らせてくれます。
assert
上の例でもあった通りテストは assert
を使って書いていきます、assertは一致を確認するassertEqual
以外にも不一致を確認するassertNotEqual
, Trueであることを確認するassertTrue
など色々な種類があります。もっと見たい人はunittestの公式ドキュメントを参照してください。
mock
testsを実行するのは実環境ではないのでどうしても実環境と違いがでてしまいうまくテストできない事が発生します。そんなときmockを使うと特定の関数の機能を上書きすることができます。実際 to2.pwではGoogleのrecaptchaを使っているのですがrecaptchaはunit testsでは再現できません、なのでmockを使いrecaptcha認証をしてるように見せ、テストコードを書きました。
↑ブラウザ上で発行されるtokenをgoogleに送信して認証するのでtestsでは実行できない
@mock.patch('urlshortner.views._verifyRecaptcha', dummy_return_true)
でurlshortner.views._verifyRecaptcha
関数を常にTrueを返すdummy_return_true
関数に置き換えて実行しています。
client
ちゃっかり上の例でも使ってたんですがtestClientを使うとAPIへのリクエストを再現できます。
上の例だと/api/urls/に意図しないパラメータのリクエストが投げられたときのステータスコードとエラーメッセージを確認しています。
まとめ
いかがでしたか testsの概念となんとなくの書き方を知ってもらえたら幸いです。大体どの言語にもtests用のフレームワークがあると思うので個人で開発するときにテストを導入したり、今年はできなかったですがプロコンの開発にテストを導入することを検討して貰えればと思います(まあ半年間 or 一人開発のプロジェクトでどこまでテストを書く効果があるかわかりませんが…)