ラベル Continuous Testing の投稿を表示しています。 すべての投稿を表示
ラベル Continuous Testing の投稿を表示しています。 すべての投稿を表示

2015年8月9日日曜日

テストデータを管理する方針

『継続的デリバリー』の、テストデータの管理についての記述を整理してみた。該当する章節は、
  • 12.5 テストデータを管理する
  • 12.6 データの管理とデプロイメントパイプライン
それから12.5から参照されている、
  • 8.5.1 受入れテストにおける状態
の3箇所。特に断りの無い限り、『継続的デリバリー』のいう受入れテストのデータ管理を念頭に置いている。

テストデータの管理で問題となるのは、1) パフォーマンス、2) テストの分離の2つ。xUTPだとそれぞれSlow TestsとSeparation of Concernsに対応しているように思う。

どちらの問題でも、真っ先に原因として挙がるのがデータベース。ユニットテストならデータベースアクセス移譲先 (デザインパターンDAO相当) をテストダブルで置き換えられる。これはパフォーマンスにも分離にも効く。DBの状態も含めてテストしたい場合、インメモリDB (H2, SQLite, JavaDBなど) を使うこともできる。

データベースに限らず、テストとデータのつながりを管理するアプローチには、次の3つがある。
  1. テストの分離: 各テスト用のデータは、そのテストからしか見えないようにする。
  2. 順応型テスト: テストがデータ環境を調べ、実際のデータに合わせて振る舞うようにする。
  3. テストの順序づけ: テストの実行順序を予め決めておいて、一つ前のテストの出力を次のテストの入力とする。
スケールするのは1だけだと言っている。3は分かりやすい無理ゲー。こんな強く依存していたらスケールさせられない。2は一見良さげに見えるけれど、分離しきれていないと、別のテストで実際のデータが思いもよらない状態になっていることがある。xUTPでもTest SmellsとしてConditional Test Logicが挙がっている。

「テストの分離」のためには、まずテスト終了時にテスト前の状態に戻すとある。そうしないと、次のテストに今のテストのデータが見えてしまう。ただこれにはオプションもある。『システムテスト自動化標準ガイド』や『実践テスト駆動開発』では、テスト対象が登録したデータはテスト終了時に消さずに、テスト開始時に消すことを勧めている。もう一つの方法は、データを機能分割すること。これができるかどうかは、テスト対象の特性に強く依存する。

データを分割し、巨大で複雑なデータ構造への依存を減らすには、まずデータを整理しないといけない。著者はこんな風に言っている。
何よりもまず、プロダクションデータのダンプを取得して受入れテスト用にテストデータベースに投入したいという誘惑に負けないこと。
統制のとれた最小限のデータセットを保守しよう。
整理の取っかかりとなるのが、次の3種類のデータの区別。
  1. テスト固有のデータ: 一意でなければならない。テストの分離の手段になる。
  2. テストが参照するデータ: テストには関係するがふるまいには影響しないデータ。そこら中で使われるマスタデータ類を指していると思う。
  3. アプリケーションが参照するデータ: アプリケーションを立ち上げるのに必要なデータ。

一言で言うと、正しく動くと分かっている(契約による設計の言葉を使うと、事前条件を満たしている)開始位置を特定し、テスト開始時にその状態を復元する。言ってしまえばこれだけなんだけれど、そのためにはテスト対象とテストデータをよく理解する必要がある。それも一部のテストだけじゃない。うまくテストを分離するには、全体を俯瞰する必要がある。

なお、その開始位置を復元するのには、アプリケーションのAPIを利用するよう勧めている。理由は3つ。
  • システムを矛盾した状態に持ち込ませない。
  • データベースやAPIのリファクタリングの影響を避けられる。
  • APIのテストにもなる。
できないときは、事前条件をアサートする防御的なテストコードにしたり、アサートを相対的(例えば、レコードが3件あることではなくて、3件増えたことにする)にしたりする。

References


2015年2月18日水曜日

継続的テスト、継続的インテグレーション、継続的デリバリー

最近、テストとビルドの関係について考え直している。『継続的デリバリー』を読み始めて少しだけまとまってきたので、整理を兼ねてメモしておく。

結論から言うと、テストとビルドの結合はこれまで考えていたよりずっと密だった。継続的インテグレーション/継続的デリバリーは継続的テストを含んでいる。スピードを上げるには〈デプロイメント・パイプライン〉を実装する必要がある。

なお〈デプロイメント・パイプライン〉は『継続的デリバリー』の中核となるパターンで、今のところ、インスペクション、コンパイル、ユニットテスト、ビルド、デプロイ、インテグレーションテスト、システムテスト、リリースなど一連のプロセスをうまく組み合わせることだと理解している。

ただ、組み合わせる範囲が広過ぎて、どこからどう手を付けたらいいのやら。『継続的デリバリー』の続きにヒントがあると期待しているのだけれど。

さて、以降はこの考えに至るまでに考えたあれやこれや。

テストとビルドは切っても切り離せない。そもそも正しい構成のテストがテスト環境にデプロイされていないと、テストする意味が無い。『ソフトウェアテスト 293の鉄則』でも、ビルドに関する鉄則が出てくる。
鉄則170 ビルドスケジュールを調整せよ
鉄則171 ビルド引き渡し前のプログラマの仕事を把握せよ
鉄則172 ビルドの受け入れ準備は怠るな
鉄則173 ときにはビルドのテスト受け入れを拒否することも大切だ
鉄則174 まずはスモークテストで判断せよ

一方で、テスターがビルドしているイメージはない。ビルドしてデプロイするのは別の役割に思える。テスターがするとしても全員ではないだろう。テストレベルが上がれば、テスターの人数が試験環境数を上回る。

〈テスト自動化〉と言ったときも、ビルドの自動化までは想像しないことが多いと思う。Javaでよく使うツールでいうとJUnitやSeleniumとかが真っ先に思い浮かんで、Antやmavenまではなかなか辿り着かない。

そのせいか、〈継続的インテグレーション〉とか〈継続的デリバリー〉と聞くと、ビルドやデプロイのことが真っ先に思い浮かんで、今度はテストがなおざりになる。

でも〈継続的インテグレーション〉について改めて『継続的インテグレーション入門』を読み返したりしてみると、テスティングやインスペクションまで含んでいる。継続的インテグレーションのベストプラクティスにも、Make the build self-testingが並んでいる。正しくビルドできたことを、テストで確認する必要があるからだと思う。

つまり、テストから見ても、ビルドから見ても、お互いに強く必要としあっている。

という論理的な帰結は論理的な帰結として、実際的な問題としてインスペクションしてコンパイルしてユニットテストしてビルドして、データベースにデータ準備して実行環境を構築して、そこにデプロイしてインテグレーションテストやシステムテストしてリリースしようなんて、膨大なスキルセットを持つユニコーンか、せめてそれぞれのエキスパートと全体を見渡すアーキテクト的なリーダを務められる人が集まらなきゃできない。

それぞれどれも大変なのに、一貫した効率的なデプロイメント・パイプラインなんて、どうしたらうまく実装できるんだろうか。

References