CIサーバーで単体テストを実行する意味は何ですか?


98

CIサーバーで単体テストを実行するのはなぜですか?

確かに、何かがマスターにコミットされる頃には、開発者はすでにすべての単体テストを実行し、新しいコードで発生した可能性のあるエラーを修正しています。それは単体テストのポイントではありませんか?そうでなければ、彼らは壊れたコードをコミットしたばかりです。


51
開発者がマスターにコミットすることは許可されていません。機能ブランチにプッシュすると、CIサーバーはマスターとマージしてテストを実行します。成功した場合変更はマスターにマージされます。壊れたテストでのように、コードすることはできませんマスターになり...
ボリス・スパイダー

2
@BoristheSpider-非常に優れたワークフロー。master常に正常であり、できれば内部QAとテスト用のステージング環境への各マージで自動的に展開する必要があります。
ランドバーグ

130
「確かに、何かがマスターにコミットされるまでに、開発者はすでにすべての単体テストを実行し、新しいコードで発生した可能性のあるエラーを修正しています。」あなたはどんなファンタジーの世界に住んでいますか?
jpmc26

5
一部の業界では、コードでテストを実行するだけでなく、バイナリでテストを実行することが重要な部分です。クライアントが受け取った正確なバイナリはすべてのテストに合格したものであるため、CI出力でテストを実行すると、提供された製品が機能することを保証できます。些細なことのように聞こえますが、これは効果がある場合があります(私が見たものは難読化です;複雑なプロジェクトで、または奇妙に設定すると、クリーンバージョンにはなかった難読化ビルドで問題を引き起こす可能性があります)。
アナキシマンダー

5
「確かに、何かがマスターにコミットされるまでに、開発者はすでにすべてのユニットテストを実行し、新しいコードで発生した可能性のあるエラーを修正しました。」...深刻かどうかわからない
16年

回答:


223

確かに、何かがマスターにコミットされる頃には、開発者はすでにすべての単体テストを実行し、新しいコードで発生した可能性のあるエラーを修正しています。

か否か。これが発生する理由はさまざまです。

  • 開発者にはそれを行う規律がありません
  • 彼らは忘れてしまった
  • 彼らはすべてをコミットせず、不完全なコミットセットをプッシュしました(Matthieu Mに感謝します
  • 彼らはいくつかのテストのみを実行しましたが、スイート全体は実行しませんでした(nhgrifに感謝)
  • 彼らはマージする前にブランチでテストしました(ありがとうnhgrif * 2)

しかし、本当のポイントは、開発者のマシンではないマシンでテストを実行することです。構成が異なるもの。

これにより、テストやコードが開発者ボックスに固有の何か(構成、データ、タイムゾーン、ロケールなど)に依存する問題を見つけることができます。

CIビルドがテストを実行するその他の理由:

  • メインの開発プラットフォーム以外の異なるプラットフォームでのテスト。これは開発者にとっては難しいかもしれません。(TZHXに感謝)
  • 受け入れ/統合/エンドツーエンド/実際に長時間実行されるテストは、通常開発者ボックスでは実行されないCIサーバーで実行される場合があります。(Ixrecに感謝)
  • 開発者は、プッシュ/コミットする前に小さな変更を加えることができます(これは安全な変更であり、したがってテストを実行しないと考えています)。(Ixrec * 2に感謝)
  • CIサーバー構成には通常、すべての開発者ツールと構成が含まれているわけではないため、実動システムにより近い
  • CIシステムは毎回プロジェクトをゼロからビルドします。つまり、ビルドは繰り返し可能です。
  • ライブラリの変更が下流の問題を引き起こす可能性があります- CIサーバが構築するように構成することができ、すべての依存のコードベースを、だけでなく、ライブラリー1

36
その他の一般的な理由:1)CIサーバーは、開発者が常に実行するのに時間がかかりすぎる高レベルの統合/受け入れテストを実行する場合があります。2)開発者はそれらを実行し、プッシュする前に小さな変更を1つ加えて、何も壊さないと確信していることを確認しましたが、確実にしたいです。
Ixrec

11
依存関係の変更は、多くの場合、すべてのダウンストリームビルドも実行します。開発者が行った変更がダウンストリームで何かを壊した場合、ライブラリを変更するとき(たとえば、基になるデータ型をSortedSetからHashSet(Setのコントラクトのみを提供する)に変更するとき)に簡単にわかりません。セットがソートされました)。CIサーバーで(ダウンストリーム)テストを実行しないと、しばらくの間そのバグが悪化します。

2
@MichaelT良いキャッチ。それが実際、最近のCI障害の90%を超える原因であり、私がそれをどのように忘れたかわからない
...-Ixrec

34
また、CI環境でそれらを実行すると、通常、プロジェクトをゼロからセットアップして、ビルドを繰り返し可能にします。
mgarciaisaia

5
また、2つの変更をコミットして別々に問題なくテストできますが、一緒に壊れます(たとえば、1つは未使用のAPIを削除し、もう1つは使用を開始します)。
サイモンリヒター

74

ソース管理にコミットする前にすべての統合テストと単体テストを実行するわけではない開発者として、ここで防御を提供します。

アプリケーションが以下で正常に動作することを構築、テスト、検証する必要があります。

  • Visual Studio 2008コンパイラを搭載したMicrosoft Windows XPおよびVista。
  • Visual Studio 2010コンパイラを搭載したMicrosoft Windows 7。
    • ああ、MSIはそれらのそれぞれに対してビルドします。
  • RHEL 5および6、それぞれ4.1および4.4(同様にCentOS)
    • 7すぐに。うんうん。
  • 最近の3つのバージョン用のGCCを備えたFedoraワークステーション。
  • 最近の3つのバージョンのDebian(およびUbuntuのような派生物)。
  • 最新の3つの最新バージョンのMac OSX。
    • パッケージ(rpm、dmgなど)

Fortran(IntelコンパイラとGNUコンパイラの両方)、Python(およびOSに応じてさまざまなバージョン)、およびbash / batスクリプトコンポーネントを追加します。

つまり、1日に2、3回テストを実行するために必要な16台のマシンです。そのためのインフラストラクチャを管理するだけでも、ほぼフルタイムの仕事になります。私はほとんど誰もがそれを不合理であることに同意するだろうと思う、特にそれをプロジェクトの人々の数に乗じる。したがって、CIサーバーに作業を任せます。

単体テストでは、壊れたコードのコミットを停止することはありません。何かを壊したことがわかっているどうかを教えてくれます。人々は「ユニットテストは高速であるべきだ」と言うことができ、原則と設計パターンと方法論に進むことができますが、実際には、反復的で単調なタスク用に設計したコンピューターにそれらを実行させ、それらが関与する場合にのみ関与させる方が良い場合があります彼らが何かを見つけたと教えてください。


3
単体テストでは、構成ではなくコードをテストします。...新しいテストを追加しても、最初のローカルで実行せずに壁の上にそれをスローするようにあなたの真剣に不活性になる
ロビーディー

33
@RobbieDee私はあなたのポイントが見えないのではないかと心配していますか?ローカルでテストせずに新しいテストを作成することや、自分でテストせずに盲目的にソース管理にコミットすることはお勧めしません。自分のマシンでテスト実行しますが、一貫した動作のために「構成」をテストする必要がありますMacを主に使用しているチームが4,000マイル離れた場所で起きてコピーを更新するときに問題を見つけるよりも、開発者の心がまだその領域にいるときに比較的迅速に行う方がよいでしょう。
TZHX

7
@RobbieDee もし可能なら、TZHXはすべてのテストをローカルで実行しますが、実行できません。TZHXはできないので、いくつかのテストをローカルで実行し(開発システムで実行でき、変更されたコードに十分に短い、または最も関連性の高いテストなど)、CIシステムで完全なバッテリーを実行します。かなり合理的です。
ムル

11
@RobbieDee:彼は単体テストを信じています。そこで、彼はMacbook Airでそれらをテストし、合格してチェックインします。その後、Red Hat、Solaris、およびWindowsを実行しているCIサーバーがそれらのテストを再度実行します。テストしたものが運用プラットフォームでも機能することを知ってうれしいですか?
スリーブマン

2
@RobbieDee:特定のプラットフォーム上の特定のコンパイラに固有の単体テストを頻繁に作成しました。たとえば、g ++(GNU C ++コンパイラ)バージョン4.5以降でのみ使用可能なAMD(Intel競合他社)固有のCPU命令を使用するグラフィックスサブシステムを考えますが、Atom CPUとICC(Intel C ++コンパイラ)。そのマシンで毎回AMD / g ++ 4.5-testsを実行するのはナンセンスですが、リリース前にテストするコードです。さらに、CPUに依存しない独自のコードは、適切な相互運用性をテストする必要があります。確かに、VMとエミュレーターがあります
...-phresnel

23

優れたOdedの回答とは別に:

  • リポジトリからコードをテストします。コミットするのを忘れたことが、ファイルを使用してマシン上で機能する可能性があります。作成スクリプト(liquibaseなど)、一部の構成データまたはプロパティファイルを持たない新しいテーブルに依存する場合があります。
  • コード統合の問題を回避できます。1人の開発者が最後のバージョンをダウンロードし、ユニットと統合テストを作成し、コードを追加し、自分のマシンですべてのテストに合格し、コミットしてプッシュします。別の開発者が同じことをしました。両方の変更はそれ自体で正しいものですが、マージするとバグが発生します。これは、リポジトリのマージ、または単に競合として検出されないことです。たとえば、Dev 1はまったく使用されなかったファイルを削除します。このファイルに対してDev 2コードを作成し、Dev 1を変更せずにテストします。
  • リポジトリから自動的にデプロイするスクリプトを開発します。普遍的な構築およびスクリプトの展開により、多くの問題が解決します。一部の開発者は、誰もが共有していないlibまたはコンパイルオプションを追加している場合があります。これにより時間を節約できるだけでなく、さらに重要なこととして、展開を安全かつ予測可能にします。さらに、リポジトリをバージョン2.3.1に戻し、このバージョンで動作するスクリプトを使用してこのバージョンをデプロイできます。これには、バージョン管理する必要があるビュー、ストアドプロシージャ、ビュー、トリガーなどのデータベースオブジェクトが含まれます。(または、実行可能なバージョンに戻ることはできません)。
  • その他のテスト:統合、パフォーマンス、エンドツーエンドテストなど。これには時間がかかる場合があり、Seleniumなどのテストツールが含まれる場合があります。モックオブジェクトやHSQLの代わりに、実際のデータベースを使用した完全なデータセットが必要になる場合があります。

私はかつて、マージおよび展開プロセスのために展開に多くのバグがあった会社で働いていました。これは、テストとCIを難しくする奇妙な所有フレームワークが原因でした。開発で完全に機能するコードが本番環境に届かなかったことを知るのは、幸せな経験ではありませんでした。


ええ、単に変更の一部をコミットするのを忘れることは非常に一般的です。私は、新しいファイルを「svn add」するのを忘れて、後でそれらをコミットするのを忘れることが、失敗した自動ビルドを取得する最も一般的な方法だと思います。
sharptooth

22

あなたはそうは思わないでしょう-しかし、開発者は人間であり、彼らは時々忘れます。

また、開発者は最新のコードをプルできないことがよくあります。最新のテストは問題なく実行され、チェックインの時点で他の誰かが重大な変更をコミットします。

テストは、ローカル(チェックインされていない)リソースに依存する場合もあります。あなたのローカルユニットテストが拾わないもの。

上記のすべてが空想的だと思う場合、Gatedと呼ばれるCI(少なくともTFS上)のレベルがあり、テストに失敗したビルドは保留され、コードベースにコミットされません。


7
私が認めようとするCIの失敗をコミットするのを忘れていたおっとを見てきました。
ダンニーリー

@DanNeely公平を期すために、それはあなたが何か... :-)について彼/彼女に言うのを忘れているので、ビルドマネージャが蹴ったお尻を取得して打つ
ロビーディー

3
それが私がCIを愛する理由の1つです。自分のooopsesを見つけて修正することは、他の誰かに見つけてもらうよりもずっと良いです。
ダンニーリー

14

何かがマスターにコミットする時までに

通常、単一のコミットごとに実行するようにCIをセットアップします。ブランチは、ブランチがテストされるまでマスターにマージされません。マスターでのテストの実行に依存している場合、ビルドが壊れるウィンドウが開きます。

CIマシンでテストを実行すると、再現可能な結果が得られます。CIサーバーにはVCSから取得した既知のクリーンな環境があるため、テスト結果が正しいことがわかります。ローカルで実行する場合、パスするために必要ないくつかのコードをコミットするのを忘れたり、失敗する必要があるときにパスするようにするコミットされていないコードを持つことができます。

また、異なるスイートを並行して実行することにより、特に各変更後にローカルで実行される可能性がない低速で数分間のテストの場合、開発者の時間を節約できます。

私の現在の仕事では、実稼働展開はすべてのテストに合格したCIに基づいています。デプロイスクリプトは、パスしない限りデプロイを防ぎます。これにより、誤ってそれらの実行を忘れることができなくなります。

CIはワークフローの一部であるため、開発者の負担も軽減されます。開発者として、通常、変更ごとにリンター、静的アナライザー、単体テスト、コードカバレッジ、統合テストを実行しますか?CIは、完全に自動的に、それについて考える必要なく、意思決定の疲労を軽減できます。


1
遅いユニットテストを実際に行うべきではありません-これは最初の原則に違反しています。
ロビーディー

4
@RobbieDee:通常、CIサーバーは単体テストだけでなく、すべてのテストを実行すると思います。
-RemcoGerlich

4
@RobbieDee:理論的にはすべての単体テストは高速です。実際には....とにかく、CIはすべてのテスト(リンター、静的分析、単体テスト、統合テスト)を実行できます。
デニス

2
@RobbieDee明らかに、構成の詳細はチームごとに異なります。ビルドに数分かかる場合でも、多くの場合、これらのビルドを並行して実行できます。単一のモノリシックコードベースを考えると、大きな欠点になる可能性がありますが、IMEは障壁ではありません。
デニス

1
@RobbieDeeそれはあなたのアーキテクチャにもっと依存すると思います。私は80人までのエンジニアリングチームのために手作業で機能するのを見てきましたが、それは製品分野の明確に定義されたサブチームと一緒です。
デニス

4

何かがマスターにコミットされるまでに、開発者すべての単体テストすでに実行しいるはずです...しかし、そうでない場合はどうでしょうか?CIサーバーで単体テストを実行しないと、他の誰かが変更を自分のマシンにプルし、テストがそれらで中断したことを発見するまでわかりません。

さらに、開発者は間違いを犯し、マシン固有のローカルリソースを参照した可能性があります。彼らがコードをチェックインし、CIの実行が失敗すると、問題はすぐに特定され、修正することができます。


3

(他の答えとは反対に)開発者は非常に規律があり、コミットする前に単体テストを実行すると仮定すると、いくつかの理由があります。

  • ユニットテストの実行には、特別な設定に時間がかかる場合があります。たとえば、メモリチェッカー(valgrindなど)を使用した単体テストの実行には、はるかに長い時間がかかる場合があります。すべての単体テストに合格していますが、メモリチェックは失敗する可能性があります。
  • 結果は、いくつかの特別な設定ではそれほど重要ではありません。たとえば、ユニットテストを実行してコードカバレッジをチェックするには、特別なコンパイルフラグが必要です。通常の開発者にとっては、コードカバレッジはそれほど重要ではありません。チームリーダーのように、コードが特定の品質を維持するように注意する人にとっては重要です。

3

変更Aがテストを中断せず、変更Bがテストを中断しないが、AとBが一緒になる場合を想像することができます。AとBが異なる開発者によって作成された場合、CIサーバーのみが新しいバグを検出します。AとBは、同じ長い文の2つの部分である場合もあります。

2台の機関車AとBによって駆動される列車を想像してください。たぶん1台で十分であり、これが適用される修正です。ただし、両方を削除して2つの「修正」を適用すると、列車は移動しません。

また、すべての開発者がすべての単体テストを実行するわけではありませんが、優秀な開発者はほとんど実行します。


2

同等の質問をしてみましょう。

CIサーバーでコードをビルドするのはなぜですか?

確かに、何かがマスターにコミットされるまでに、開発者はすでにコードを構築しており、新しいコードで発生した可能性のあるエラーを修正しています。それはコードを構築するポイントではありませんか?そうでなければ、彼らは壊れたコードをコミットしたばかりです。


CIを実行する理由はいくつかありますが、CIの主なポイントは、コードの状態が時間とともにどのようなものかを把握することです。これが提供する主な利点(いくつかあります)は、ビルドがいつ壊れるかを見つけ、何が壊れたのかを把握してから修正できることです。

コードが破損しない場合、なぜCIを使用するのでしょうか?テスト用のビルドを提供するには、ナイトリービルドで十分です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.