たごもりすメモ

コードとかその他の話とか。

GAE/Pythonテスト環境に欲しいもの

いまPython on GAEのテスト環境の貧弱さをなんとかするべく、あれこれやってる。とにかくテスト環境がショボいんだよね。

App Engine/Pythonはローカルのデータストアのstubの出来が良くないので、ローカルとプロダクションで動きが違うことが結構あり、ローカルでテストできることが限られてしまいます。Javaの方は、Statisticsの機能を除いては、ローカルとプロダクションの動きはほとんど同じです。stubレベルでは、ローカルでプロダクションと違う部分もあったりしますが、Slim3でおなじになるように実装してたりするので、ほとんど違いがないのです。

プロが仕事で使う場合にApp Engineでどの言語を選べばいいのか - ひがやすを blog

ぐうの音も出ない! 事実だ!

じゃ、プロならJavaを使った方がいいかというとそんなこともありません。好きで慣れている方を使った方が効率いいからね。

ただ、プロが仕事で使う場合には、リファクタリングやテストのしやすさは、非常に重要なポイントです。その点ではApp Engine/Javaが優れているということは知っておいた方がいい。テストのしやすさは、ソフトウェアの問題なので、改善することが可能です。今回わざわざ指摘したのは、改善されることを期待しているからです。お互いに良いところは学び、悪いところは改善していけばいい。

プロが仕事で使う場合にApp Engineでどの言語を選べばいいのか - ひがやすを blog

これも事実だと思うんだよね。自分はJavaだと思考をコードに落とす時点であまりに巨大なコストがかかっちゃうから、どうしてもJavaでは書く気になれない。(仕事で書けと言われりゃ書くけどさ、趣味じゃなあ……。)
ということでPython on GAEのテスト環境を改善したいよね。
あとリファクタリングのしやすさの問題というのは、詰まるところテストがきちんと書かれてるかって問題だと思う。ので、テストが書きやすくなればOKだよね!

テスト環境に何が欲しいか?

本題。いま作ってるand/or作ろうと思ってるのは以下の通り。できるだけ広く使えれば嬉しいので、これを読んだみなさま、コレが欲しい!とかこうでないとやだ!とかいうのを教えてもらえると幸いです。

実装済みorほぼ実装済みのもの
  • ユニットテスト実行準備
    • コンソールからunittestを実行するときに使うもの
      • 今だと自分で書くかnose-gaeに頼ってる部分
    • 必要なモジュール類のimport実行
    • 必要なServiceStubのセットアップとapiproxyへの登録
  • GAEUnitでのテスト実行時に正常に動作する状態を維持
    • production環境でのテスト実行への布石
    • kotoriに負けないぞ! HTTPインターフェイスはもうあるし!w
  • remote_apiを使用可能にする機構
    • 各テストケース内での指定があった場合に既定のテスト用スタブのかわりに有効にする
      • ただしGAEUnitでのテスト実行時には指定があってもremote_apiは使用しない(認証情報が取得できないので)
    • apiproxyを経由するすべての操作をremote_api経由でproduction環境に投げるようにする
    • productionへ接続するためのアカウント情報の入力は一度だけ
  • production環境でproduction DatastoreServiceへの操作を実行
    • GAEUnitのユニットテスト動作に割り込んで本物のDatastoreにアクセスする
      • GAEUnitはunittest動作環境をdatastore_file_stubを使うようセットアップするので、それをチャラにする
  • テスト実行時に本番とは異なるkindを使用する
    • Modelのコードはそのままで、本番環境とは違うkindを使用してテストする
    • class Hoge(db.Model) だったらkindは test_Hoge になる、みたいな感じ
    • これは多分Javaにはできないはずだ! これで勝つる!w
      • と思ったがどうだろう
      • (4/28追記) Javaでもできるらしい! 残念!w (コメント欄より)
実装方針を迷ってるもの
  • テスト終了時の処理
    • TestCaseで指定すれば関係するEntityを削除できるようにする
      • テスト専用kindでのテスト実行ができるならkind全体を削っちゃえば? と思ってたが、エンティティ単位での制御が必要か?
      • 選択式でエンティティ単位の制御ができるようにしてもいいけど、パフォーマンス落ちそうだなあ
  • テスト環境の切り替え
    • 通常のdev環境*1なら読み込むファイルの切り替えで対処可能
    • production環境ならkindのprefix('test_'とか)を切り替えればできるかな
    • TestCase記述の側から簡単に指定できると嬉しい? かな?
  • コントローラのテスト
実装したいけどまだ全然書いてないもの
  • productionのDatastoreStubと同等の動作をするDatastoreTestStub
    • 速度は諦めて、トランザクション等の機能面でproductionと同じ動作をするもの*2
    • datastore_file_stubのデータファイルを読み込めること
    • Timeout、Read-OnlyやNotAppliedなどはシミュレートできるようにしたい
      • TimeoutやNotAppliedは一定確率で起きるなど指定できるようにしたいが、ユニットテストに対してはあまり意味がない気がするなあ
      • コントローラのテストに対しては意味があるか?
ところで

元々書く予定だったものが完全放置なんだが俺はどうすれば。体がふたつ欲しい。w

*1:DatastoreFileStubとDatastoreSqliteStub

*2:このためにproductionのDatastoreに対するテストコードが欲しくて、いまあれこれ書いてるところ