現在の製品で増え続ける統合テストをスケーリングするための手法と戦略を調査しています。これにより、それらはcan(人間的に)開発の一部であり続けることができます。そしてCIプロセス。
約200以上の統合テストでは、1時間のマークに達して(デスクトップ開発マシンで)完全なテスト実行を完了しており、これは開発者がルーチンのプッシュプロセスの一部としてスイート全体を実行することを許容する能力に悪影響を及ぼしています。これは、それらをうまく作成することについて訓練される動機に影響を与えています。主要なシナリオのみを前面から背面まで統合してテストし、テストの実行ごとにゼロから構築された、本番環境を反映した環境を使用します。
実行に時間がかかるため、テストランがどれだけ集中していても、マシンがテストランを完了するのを待つのはひどいフィードバックループと多くの無駄なサイクルになっています。フローと進行、健全性、持続可能性へのより高価な負の影響を気にしないでください。
この製品の速度が低下し始める前に、統合テストが10倍になると期待しています(実際にはわかりませんが、機能に関してはまだ始まったとは言えません)。私たちは、数百または数千の統合テストに参加することを合理的に期待する必要があります。
明確に言うと、これが単体テストと統合テストの議論になることを防ぐために(トレードすべきではありません)。この製品では、TDDを使用した単体テストと統合テストの両方を行っています。実際、私たちはverifyする必要があるので、私たちが理解しているサービスアーキテクチャのさまざまなレイヤーで統合テストを行っています。ここで、アーキテクチャのパターンをシステムの他の領域に変更するときに、重大な変更を導入します。
技術スタックについて少し。現在、CPUとメモリを集中的に使用するエミュレーション環境でテストを行っており、エンドツーエンドでテストを実行しています。これは、Azure REST noSqlバックエンド(ATS)に対応するWebサービスで構成されています。Azureデスクトップエミュレーター+ IISExpressで実行することにより、本番環境をシミュレートしています。1つのエミュレーターと1つのローカル開発マシンごとのバックエンドリポジトリ。
また、同じエミュレート環境で同じテストを実行するクラウドベースのCIもあり、現在のCIプロバイダーのクラウドではテスト実行に2倍の時間がかかります(2時間以上)。クラウドCIプロバイダーの制限に達しましたSLAハードウェアパフォーマンスの点で、テスト実行時の許容値を超えました。公平に言うと、仕様は悪くありませんが、半分は明らかに社内の汚れたデスクトップマシンとして良い。
テストの論理グループごとにデータストアを再構築し、テストデータをプリロードするテスト戦略を使用しています。データの整合性を包括的に保証しながら、これにより各テストに5〜15%の影響が加わります。したがって、製品開発のこの時点では、そのテスト戦略を最適化することで得られるものはほとんどないと思います。
その長所と短所は次のとおりです。各テストのスループットを最適化することはできますが(それぞれ30%-50%程度であっても)、近い将来、数百のテストで効果的にスケーリングすることはできません。今でも1時間は人間が許容できるレベルをはるかに超えており、持続可能にするためにはプロセス全体で桁違いの改善が必要です。
そこで、テスト時間を大幅に短縮するために採用できる手法と戦略について調査しています。
このスペースで他の人が使用している戦略(およびツール)を確認したかったのです。
(私は他の人が特定のテクノロジーセットを使用してこの種の困難を経験しているかもしれないと信じなければなりません。))
[更新:2016年12月16日:結果の議論のために、CI並列テストにさらに投資することになりました: http://www.mindkin.co.nz/blog/2015/12/16/ 16ジョブ]
統合テストを実行するのに5時間(30台のマシンで)かかる場所で働いていました。私はコードベースをリファクタリングし、代わりに新しいもののために単体テストを行いました。単体テストには30秒かかりました(1台のマシンで)。ああ、そしてバグも減りました。そして、私たちが知ってからの開発時間正確に細かいテストで壊れたもの。
一言で言えば、そうではありません。完全な統合テストは、コードベースが大きくなるにつれて指数関数的に大きくなります(コードが増えるほど、テストが増え、コードが増えるということは、「統合」が進むにつれて、すべてのテストの実行時間が長くなることを意味します)。フィードバックループがないため、「時間」の範囲にあるものはすべて、継続的インテグレーションの利点のほとんどを失うと私は主張します。桁違いの改善でさえ、あなたを良いものにするのに十分ではありません-そして、あなたをスケーラブルにするのに近いところはありません。
そのため、統合テストを最も広く、最も重要な煙のテストに削減することをお勧めします。その後、それらは夜間または連続的ではない間隔で実行でき、パフォーマンスの必要性の多くを削減します。ユニットテストは、コードを追加するにつれて直線的に成長するだけです(テストは増加しますが、テストごとのランタイムはそうではありません)。
統合テストは実際のユーザーを模倣する必要があるため、常に長時間実行されます。このため、これらすべてを同期的に実行しないでください。
あなたはすでにクラウドで何かを実行していることを考えると、あなたは複数のマシンにまたがってテストをスケーリングする絶好の位置にいるように思えます。
極端な場合は、テストごとに1つの新しい環境を起動し、それらすべてを同時に実行します。統合テストは、実行時間の最も長いテストと同じくらいの時間がかかります。
テストを削減/最適化することは私にとって最良の考えのようですが、それが選択肢ではない場合は、提案する代替案があります(ただし、いくつかの単純な専用ツールを構築する必要があります)。
私は同様の問題に直面しましたが、統合テストでは発生しませんでした(それらは数分で実行されました)。代わりに、それは単に私たちのビルドにありました:大規模なCコードベースは、ビルドに数時間かかります。
全体をゼロから再構築している(約20,000のソースファイル/コンパイルユニット)ことは非常に無駄であると私が考えたのはソースファイルが変更されたため、最悪の場合数秒または数分しかかからない変更に数時間を費やしています。
そのため、ビルドサーバーでインクリメンタルリンクを試しましたが、それは信頼できませんでした。それは時々偽陰性を与え、いくつかのコミットでビルドに失敗し、完全なリビルドでしか成功しませんでした。さらに悪いことに、開発者が壊れたビルドをメインブランチにマージする場合にのみ、誤検知が発生してビルドの成功が報告されることもあります。そこで、開発者がプライベートブランチから変更をプッシュするたびに、すべてを再構築することに戻りました。
私はこれがとても嫌いでした。私は、開発者の半分がビデオゲームをプレイしている会議室に足を踏み入れました。ビルドを待っている間にコードで作業できるように、コミットしたらマルチタスクを実行して新しいブランチを開始し、生産性Edgeを取得しようとしましたが、テストまたはビルドが失敗すると、その時点を過ぎて変更をキューに入れるのが面倒になりましたそして、すべてを修正して、すべてを元に戻すようにしてください。
待機中のサイドプロジェクト、後で統合
代わりに、私が代わりに行ったのは、アプリケーションの骨格フレームワークを作成することでした-まったく別のプロジェクトとして開発するために、同じ種類の基本的なUIとSDKの関連部分。次に、メインプロジェクトの外で、ビルドを待機している間に、それに対して独立したコードを記述します。これにより、少なくとも生産性を維持できるようにコーディングを行うことができました。その後、製品の完全に外部で行われた作業を後でプロジェクトに統合します-コードのサイドスニペット。開発者が多くの時間を待っている場合、これは開発者にとって1つの戦略です。
ソースファイルを手動で解析して、何を再構築/再実行するかを把握する
それでも、私はすべてを常に再構築するために非常に多くの時間を浪費していたのが嫌いでした。そのため、私は週末に数週間かけて、実際にファイルをスキャンして変更を確認し、関連プロジェクトのみを再構築するコードを作成しました-完全な再構築であり、インクリメンタルリンクはありませんが、再構築が必要なプロジェクトのみ(依存ファイルが再帰的に解析され、変更された)。それは完全に信頼でき、徹底的にデモンストレーションおよびテストした後、そのソリューションを使用することができました。必要なプロジェクトのみを再構築していたため、平均ビルド時間は数時間から数分に短縮されました(ただし、中央のSDKの変更にはまだ1時間かかる可能性がありますが、ローカライズされた変更ほど頻繁ではありません)。
同じ戦略が統合テストにも適用できるはずです。ソースファイルを再帰的に解析して、統合テストがどのファイルに依存しているかを調べます(例:Javaではimport
、#include
(CまたはC++の場合)、サーバー側、およびそれらのファイルからインクルード/インポートされたファイルなど。システムの完全なインクルード/インポート依存関係ファイルのグラフを構築します。 DAGを形成するビルド解析とは異なり、グラフは、間接的に実行される可能性のあるコードを含む変更されたファイルに関心があるため、無向である必要があります*。目的の統合テストのグラフ内のファイルのいずれかが変更された場合にのみ、統合テストを再実行します。数百万行のコードであっても、この解析は1分未満で簡単に実行できました。コンテンツファイルのように、統合テストに影響を与える可能性のあるソースコード以外のファイルがある場合は、統合テストの依存関係を示すメタデータをソースコードのコメントに書き込んで、これらの外部ファイルが変更された場合に、テストを行うこともできます。再実行してください。
*例として、test.cにfoo.cにも含まれているfoo.hが含まれている場合、test.c、foo.h、またはfoo.cのいずれかを変更すると、統合テストに新しい実行が必要であることが示されます。
これは、特に正式な環境では、プログラミングとテストに1日または2日かかる可能性がありますが、統合テストでも機能するはずであり、ビルドの時間範囲で待つ以外に選択肢がない場合は、それは価値があります。完成する(ビルド、テスト、パッケージングのプロセスなどにより)。これは、このような独自のソリューションを構築するのにかかる時間を短縮するだけでなく、チームのエネルギーを殺し、より大きなマージでの競合によって引き起こされるストレスを増大させるだけでなく、ほんの数ヶ月で失われる非常に多くの工数につながる可能性がありますすべての時間を無駄に待っていた結果として頻繁に。彼らが物事を待つために時間の大部分を費やしているとき、それはチーム全体にとってちょうど悪いことです。最適化する最も簡単で最も一般的な方法は、すべての変更がすべてをリビルド/再実行/再パッケージ化する必要があるわけではないという事実を単に認識することです変化する。
統合テストが多すぎるようですね。リコール ピラミッドのテスト 。統合テストは真ん中に属しています。
例として、メソッドset(key,object)
、get(key)
を持つリポジトリを取り上げます。このリポジトリは、コードベース全体で広く使用されています。このリポジトリに依存するすべてのメソッドは、偽のリポジトリでテストされます。これで、2つの統合テストのみが必要です。1つはセット用、もう1つは取得用です。
これらの統合テストの一部は、おそらく単体テストに変換できます。たとえば、私のビューのエンドツーエンドのテストでは、サイトが正しい接続文字列とドメインで正しく構成されていることのみをテストする必要があります。
統合テストでは、ORM、リポジトリ、およびキューの抽象化が正しいことをテストする必要があります。経験則として、統合テストにドメインコードは必要ありません。抽象化のみです。
他のほとんどすべては、依存関係のスタブ化/モック化/偽装/メモリ内実装を使用して単体テストできます。
継続的デリバリーパイプラインが一般的であるアジャイル環境またはDevOps環境での私の経験では、各モジュールが完成または調整されるときに統合テストを実行する必要があります。たとえば、多くの継続的デリバリーパイプライン環境では、開発者ごとに1日に複数のコードをデプロイすることは珍しくありません。このタイプの環境では、展開前の各開発フェーズの最後に統合テストのクイックセットを実行するのが標準的な方法です。追加情報については、この主題に関するあなたの読書に含める優れたeBookは、Katrina Clokieによって書かれた DevOpsでのテストの実践ガイド です。
この方法で効率的にテストするには、専用のテスト環境で既存の完成したモジュールに対して、またはスタブとドライバーに対して新しいコンポーネントをテストする必要があります。必要に応じて、各アプリケーションモジュールのスタブとドライバのライブラリをフォルダまたはライブラリに保持して、迅速な反復的な統合テストの使用を可能にすることをお勧めします。このようにスタブとドライバーを整理しておくと、反復的な変更を簡単に実行でき、継続的なテストのニーズを満たすためにそれらを更新して最適に実行できます。
考慮すべきもう1つのオプションは、サービス仮想化と呼ばれる、もともと2002年頃に開発されたソリューションです。これにより仮想環境が作成され、複雑なエンタープライズDevOpsまたはアジャイル環境でのテスト目的で、既存のリソースとのモジュールの相互作用がシミュレートされます。
この記事は、実行方法の詳細を理解するのに役立ちます 企業での統合テスト
ある時点で、統合テストの完全なセットは、高価なハードウェアであっても、完了するまでに何時間もかかる場合があります。オプションの1つは、すべてのコミットでこれらのテストの大部分を実行せず、代わりに毎晩、または連続バッチモード(複数のコミットごとに1回)で実行することです。
ただし、これは新しい問題を引き起こします-開発者はすぐにフィードバックを受け取らず、壊れたビルドは気付かれない可能性があります。これを修正するには、何かが常に壊れていることを彼らが知っていることが重要です。 Catlight または TeamCityのトレイ通知機能 のような通知ツールを作成すると、非常に便利です。
しかし、さらに別の問題があります。ビルドが壊れていることを開発者が確認した場合でも、彼はそれをチェックするために急いでいません。結局のところ、誰かがすでにそれをチェックしているのではないでしょうか?
そのため、これら2つのツールには「ビルド調査」機能があります。開発チームの誰かが実際に壊れたビルドをチェックして修正しているかどうかを通知します。開発者はボランティアでビルドを確認でき、それが完了するまで、チームの全員が時計の近くにある赤いアイコンに悩まされます。
各テストを測定して、時間がかかっている場所を確認しましたか?そして、特に遅いビットがある場合、コードベースのパフォーマンスを測定しました。全体的な問題は、テストまたは展開のどちらか、または両方ですか?
通常は、統合テストの影響を減らして、比較的小さな変更での実行を最小限に抑える必要があります。次に、ブランチが次のレベルに昇格したときに実行する「QA」実行の完全なテストを終了できます。そのため、開発ブランチの単体テストがあり、マージ時に統合テストを減らし、リリース候補ブランチにマージすると完全統合テストを実行します。
つまり、すべてのコミットをすべて再ビルドして再パッケージ化して再デプロイする必要はありません。開発環境でセットアップを編成して、大丈夫であると信頼して、可能な限り安価なデプロイメントを実行できます。 VM全体をスピンアップして製品全体をデプロイする代わりに、VMを古いバージョンのままにして、新しいバイナリを所定の場所にコピーします(たとえば、YMMVは必要な作業によって異なります)。 。
この全体的な楽観的なアプローチでは、まだ全面的なテストが必要ですが、それは、時間がかかる緊急度が低い後の段階で実行できます。 (たとえば、開発者が朝に解決できる問題がある場合は、夜間に1回完全なテストを実行できます)。これには、翌日のテストのために統合リグの製品を更新するという利点もあります。開発者が変更するため、1日しか経てない可能性があります。
セキュリティベースの静的分析ツールを実行すると、同様の問題が発生しました。フルランには時間がかかるため、開発者のコミットから統合コミットに実行を移しました(つまり、開発者が完了したと言うシステムがあり、パフォーマンスを含むより多くのテストが実行される「レベル2」ブランチにマージされました)テスト。これが完了すると、展開のためにQAブランチにマージされます。アイデアは、毎晩実行される実行に対して継続的に発生する定期的な実行を削除することです。開発者は朝に結果を取得し、開発に影響を与えません。開発サイクルの後半まで集中します)。
CIパイプライン統合テスト(またはビルドを含むあらゆる種類の検証)を維持するための別の可能なアプローチは、実行時間が長いか、限られたリソースや高価なリソースを必要とするに基づく従来のCIシステムから切り替えることです。コミット後の検証( 輻輳 の影響を受けやすい)は、コミット前の検証に基づいたものに。
ブランチ開発者に変更を直接コミットする代わりに、検証を実行する集中型自動検証システムに変更を提出します。
このようなアプローチにより、送信された複数の変更を組み合わせてテストすることが可能になり、効果的なCI検証速度が何度も向上する可能性があります。
そのような例の1つは OpenStackで使用されるGerrit/Zuulベースのゲーティングシステム です。
もう1つは ApartCI (disclaimer-私はその作成者であり、それを提供する会社の創設者です)。
コードベースが大きくなっているようですが、コード管理が役立ちます。私たちはJavaを使用しています。
Java私が作業しているショップはこのアプローチを使用しており、統合テストが実行されるのを待つことはほとんどありません。