バージョン管理フックで単体テストを実行するのは良い習慣ですか?


43

技術的な観点から、特定のコミットをリモートのデフォルトブランチにマージする前に、ユニットテストを実行する事前/事後プッシュフックを追加することができます。

私の質問は-ビルドパイプラインでユニットテストを保持する(つまり、破損したコミットをレポに導入する)方が良いのか、それとも「悪い」コミットが発生しないようにする方が良いのかです。

私は、この2つのオプションに制限されていないことを理解しています。たとえば、マージコミットをレポジトリにプッシュする前に、すべてのコミットの分岐とテストを許可できます。しかし、この2つのソリューションを正確に選択する必要がある場合、どちらを選択しますか。


回答:


35

いいえ、そうではありません。2つの理由からです。

速度

コミットは高速でなければなりません。たとえば、500ミリ秒かかるコミットは遅すぎるため、開発者はより慎重にコミットする必要があります。Hello Worldよりも大きなプロジェクトでは、数十または数百のテストがあるため、事前コミット中に実行するには時間がかかりすぎます。

もちろん、分散アーキテクチャで数分間、または単一のマシンで数週間または数か月実行される数千のテストがある大規模プロジェクトでは、事態はさらに悪化します。

最悪の部分は、より速くするためにできることはあまりないということです。たとえば、100のユニットテストがある小規模なPythonプロジェクトは、平均的なサーバーで実行するのに少なくとも1秒かかりますが、多くの場合それよりはるかに長くなります。C#アプリケーションの場合、コンパイル時間のため、平均で4〜5秒かかります。

その時点から、より良いサーバーに余分な1万ドルを支払うことで時間を短縮できますが、それほど多くはしないか、複数のサーバーでテストを実行します。

数千のテスト(機能テスト、システムテスト、および統合テスト)がある場合は両方とも十分に効果があり、数週間ではなく数分でテストを実行できますが、これは小規模プロジェクトには役立ちません。

代わりに、できることは:

  • 開発者がコミットする前に、ローカルで変更したコードに強く関連するテストを実行することを奨励します。おそらく数千の単体テストを実行することはできませんが、5〜10を実行できます。

    関連するテストを見つけて実行することが実際に簡単(かつ高速)であることを確認してください。たとえば、Visual Studioは、最後の実行以降に行われた変更によって影響を受ける可能性のあるテストを検出できます。他のIDE /プラットフォーム/言語/フレームワークにも同様の機能があります。

  • コミットを可能な限り高速に保ちます。スタイルルールを適用することは問題ありません。多くの場合、スタイルルールを実行する唯一の場所であり、このようなチェックは驚くほど高速だからです。静的解析は、高速のままであればすぐに実行できますが、これはめったにありません。単体テストの実行は問題ありません。

  • Continuous Integrationサーバーで単体テストを実行します。

  • 開発者がビルドを破ったとき(またはユニットテストが失敗したとき、開発者に自動的に通知されることを確認します。これは、コンパイラをコードに持ち込む可能性のある間違いの一部をチェックするツールと見なす場合、事実上同じです)。

    たとえば、Webページにアクセスして最後のビルドを確認することは解決策ではありません。それらは自動的に通知される必要があります。ポップアップの表示またはSMSの送信は、ポップアップの通知方法の2つの例です。

  • 開発者は、ビルドを壊す(または回帰テストに失敗する)ことは良くないこと、そしてそれが起きたらすぐに修正することが最優先事項であることを理解してください。上司が明日出荷するように求めた優先度の高い機能に取り組んでいるかどうかは関係ありません。ビルドに失敗したので、修正する必要があります。

セキュリティ

リポジトリをホストするサーバーは、特にセキュリティ上の理由から、単体テストなどのカスタムコードを実行しないでください。これらの理由は、GitLabの同じサーバー上のCIランナーで既に説明されていますか?

一方、ビルドサーバーでpre-commitフックからプロセスを起動することを考えている場合は、コミットがさらに遅くなります。


4
私は同意します、これがビルドサーバーの目的です。ソース管理はソースコードを管理するためのものであり、アプリケーションの動作を保証するものではありません。
マシュー14年

4
極端な場合、報復はビルドを壊すときに必要な通知ツールになる場合があります。

37
半秒が遅すぎる?これは、コミットされている内容を最後に見てから、適切なコミットコメントを考えて入力するのに比べて、バケットの数が少ないことです。
ドーバル14年

5
@Doval:違いは、あなたが1つの最終的な外観を与えるか、またはコメントについて考えるとき、あなたがしていることで積極的、かつので、あなたが待っていません。IDEで最後の文字を入力する前に費やす時間ではなく、コミットが終了してから再び入力を開始できる時間ではなく、どれだけ待つ必要があります。それがコンパイラが高速であるべき理由です。コードの読み取りと書き込みにもっと多くの時間を費やすことは問題ではありません。コードをコンパイルしているときは別のアクティビティに切り替えたいと思うのに対して、コードを読み書きするのは待つ必要がないからです。
Arseni Mourzenko

10
@Thomas:それは気を散らすものではなく、迷惑なものです。同様に、100ミリ秒。人がWebサイトをどのように使用しているかに「測定可能な影響」があります。ここに同じパターン:100ミリ秒。YouTubeビデオの視聴やPCの起動に費やす時間と比較して何もありません。意識的に、600ミリ秒の違いに気付かないでしょう。および700ミリ秒。ディレイ。しかし、無意識のうちに、それはあなたの行動に影響を及ぼします。同様に、少し遅いコミットは、あなたが早期に頻繁にコミットすることを思いとどまらせます。
Arseni Mourzenko

41

私が仲間の回答者と意見が合わないようにしましょう。

これは、TFSの世界ではゲートチェックインとして知られています。ゲートチェックインを使用してブランチにチェックインしようとすると、シェルブセットがサーバーに送信されます。これにより、変更がビルドされ、指定された(読み取り:すべての)単体テストがパスします。そうでない場合、ビルドを壊したのは悪いサルだということを通知します。そうした場合、変更はソース管理に反映されます(はい!)。

私の経験では、ゲートチェックインはユニットテストを成功させるための最も重要なプロセスの1つであり、ひいてはソフトウェアの品質です。

どうして?

  • ゲートチェックインにより、壊れたテストを修正する必要があるためです。壊れたテストは、やらなくてはならないことができるようになるとすぐに、怠zyなエンジニアや強引なビジネスマンによって優先順位が下がります。
    • テストが中断される時間が長いほど、修正が難しくなります(そしてコストがかかります)。
  • すぐに人々が通りますので必要がありますテストを実行するのではなく必要がありますテストを実行して、テストを実行怠惰/忘れっぽいエンジニアおよび/または強引なビジネスの人々によって回避されています。
  • ユニットテストがコミット時間に影響を与えるとすぐに、人々は本当にテストをユニットテストにすることを気にし始めるからです。スピードが重要です。再現性が重要です。信頼性が重要です。分離が重要です。

そしてもちろん、元々持っていた利点があります-チェックインとテストの強固なスイートをゲートすると、すべての変更セットが「安定」します。「最後の適切なビルドはいつだったか」というオーバーヘッド(およびエラーの可能性)をすべて節約できます。-すべてのビルドは開発に対して十分に優れています。

はい、テストをビルドして実行するには時間がかかります。私の経験では、適切なサイズのC#アプリと5k単位のテストで5〜10分です。そして、私はそれを気にしません。はい、頻繁にチェックインする必要があります。しかし、タスクを頻繁に更新したり、メールをチェックしたり、その時間を占めるソフトウェアエンジニアの仕事を構成するコーヒーやその他の「コードに取り組んでいない」ものを手に入れる必要もあります。不良コードのチェックアウトは、5〜10分よりもはるかにコストがかかります。


3
+1私が付け加えたいのは、多くのオープンソースプロジェクトには貢献とコミットの明確な区別があるということです。その理由は、ゲートチェックインが存在する理由と非常に似ています。
JensG 14年

ゲートチェックインの重要な問題の1つは、困難なコードの共同問題解決を妨げることです。これは、分散チームではさらに重要です。
CuriousRabbit

2
@CuriousRabbit-どのように考えますか?人々が協力して働いても、共同でコミットすることはめったにありません。それ以外の場合、シェルフセットまたは日付のないタスクブランチは、チームの他のメンバーを妨げることなく、そのために有効に機能します。
テラスティン14年

@ Telastyn– Shelvesetsは私にとっての新しい用語です。これはMS VSのオプションであり、膨大な数のプロジェクトのオプションではないということです。モバイルアプリ開発の分野では、VSはノンプレイヤーです。
CuriousRabbit 14年

3
@CuriousRabbit-本当に?17時間にわたって分散されたチームは、問題のあるパーティが眠っている間にビルドが壊れる可能性よりも、コミットを10分間待つことを重視していますか?それは...最適とは言えません。
テラスティン14年

40

コミットは高速に実行されるはずです。いくつかのコードをコミットするときに、サーバーにプッシュするようにします。一連のテストを実行している間、数分待ちたくありません。私はサーバーにプッシュするものに対して責任があり、コミットフックで私をベビーシッターにする必要はありません。

ただし、サーバーに到達したら、すぐに(または短時間で)分析、単体テスト、および構築する必要があります。これは、単体テストが壊れているか、コンパイルされなかったという事実、または利用可能な静的分析ツールで表示される混乱を警告します。これが速く行われる(ビルドと分析)、フィードバックが速くなり、修正が早くなります(思考が完全に脳から外れるわけではありません)。

いいえ、クライアントのコミットフックにテストなどを入れないでください。必要な場合は、ポストコミット(CIサーバーがないため)またはCIビルドサーバーでサーバーに配置し、コードの問題を適切に通知してください。ただし、そもそもコミットの発生をブロックしないでください。

また、テスト駆動開発のいくつかの解釈では、最初に破損する単体テストチェックインする必要があることも指摘する必要があります。これは、バグが存在することを示し、文書化します。その後、後のチェックインは、単体テストを修正するコードになります。ユニットテストに合格するまでチェックインを禁止すると、問題の文書化に失敗したユニットテストでのチェックの実効値が低下します。

関連:既知の欠陥の単体テストが必要ですか?そして、失敗した単体テストをチェックすることの価値は何ですか?


2
Commits should run fast.これの利点は何ですか?現在、ゲートチェックインを使用しているので、興味があります。通常、私のチェックインは1時間程度の作業の累積であるため、5分間の待機は大したことではありません。実際、私はそのその通常の倍見つけた検証ビルドが(急いの結果として)愚かなミスをキャッチするために最も有用であることを急いで
ジャスティン・

1
@Justin 5分間の待機は、どこにいても5分間の待機です。一つはいけません、あなたがコミットしないたびにNERF剣を抜け出す必要があります。そして、1時間程度の作業を、それぞれ概念的な単位である複数のコミットに分割することは珍しくありません。 (別のコミットとしてのcss調整は言うまでもありません)。これらのそれぞれの実行に5分かかった場合、私の時間の6分の1がテストの待機に費やされます。これにより、バグを追跡するのが難しいロールアップコミットが大きくなります。

単体テストの実行に5分間待機しますか?皆さんが取り組んでいるプロジェクトは、小さなコンポーネントに分割されるべきだと思います。
user441521

@ジャスティンcatching silly mistakes (as a result of rushing)まさに。一般に、急ぐことはソフトウェアエンジニアリングの悪い習慣です。ロバートC.マーティンは、手術をするようなコードを書くことをお勧めしますyoutube.com/watch?v=p0O1VVqRSK0
ジェリージョセフ

10

原則として、人々がメインラインに変更を加えてビルドを壊さないようにすることは理にかなっていると思います。つまり、リポジトリのメインブランチを変更するプロセスでは、すべてのテストに合格することを確認する必要があります。ビルドを壊すことは、プロジェクトのすべてのエンジニアが他のことをするための時間のロスという点で、あまりにも高価です。

ただし、コミットフックの特定のソリューションは適切な計画ではありません。

  1. 開発者は、コミット中にテストの実行を待つ必要があります。開発者がすべてのテストに合格するまでワークステーションで待たなければならない場合、貴重なエンジニアの時間を無駄にします。エンジニアは、テストが失敗したために元に戻さなければならない場合でも、次のタスクに進むことができる必要があります。
  2. 開発者は、ブランチで壊れたコードをコミットしたい場合があります。より大きなタスクでは、開発者バージョンのコードは合格状態ではなく、多くの時間を費やす可能性があります。明らかに、そのコードをメインラインにマージすることは非常に悪いでしょう。ただし、開発者がバージョン管理を使用して進行状況を追跡できることはかなり重要です。
  3. プロセスをスキップしてテストをバイパスする理由はときどきあります。

2
#1は、開発者が個人のブランチまたはローカルリポジトリにチェックインできるようにすることで不要になります。単体テストを実行する必要があるのは、開発者が自分のコードをどこかで見たい場合にのみ、他の開発者がそれを見ることができるということです。#1と同様に、#2はメインラインブランチへのフックのみで不要になります。#3は、A)面倒(および面倒であるべき)であるにもかかわらず、そのような機能を無効にできるという事実と、B)失敗した個々の単体テストを無効にできるという事実によって回避されます。
ブライアン14年

@ブライアン、私は完全に同意しています、あなたはこの仕事をすることができます。ただし、サーバー側のコミットフックをブロックしてやろうとしてもうまくいきません。
ウィンストンイーバート14年

良い点。 Breaking the build is simply too costly in terms of lost time for all engineers on the project私は、各壊れたビルドに時間を失う終わるすべてのエンジニアを避けるために、ビルド通知ツールのいくつかの種類を使用することをお勧めし
ジェリー・ジョセフ

3

いいえ、他の回答が指摘しているように、あなたはすべきではありません。

失敗するテストがないことが保証されているコードベースが必要な場合は、代わりに機能ブランチで開発し、マスターにプルリクエストを行うことができます。次に、これらのプル要求を受け入れるための前提条件を定義できます。利点は、本当にすばやくプッシュできることと、テストがバックグラウンドで実行されることです。


2

メインブランチへのコミットごとにビルドとテストが成功するのを待たなければならないのは本当にひどいです。誰もがこれに同意すると思います。

ただし、一貫したメインブランチを実現する方法は他にもあります。TFSのゲートチェックインの流れに少し似ていますが、ブランチを使用するバージョン管理システムに一般化できる1つの提案がありますが、主にgit用語を使用します。

  • 開発ブランチとメインブランチ間のマージのみをコミットできるステージングブランチがあります。

  • ビルドを開始またはキューに入れ、ステージングブランチで行われたコミットをテストするフックを設定しますが、コミッターは待機しません

  • ビルドとテストが成功すると、メインブランチが最新の場合に自動的に前に進みます

    注:メインブランチに自動的にマージしないでください。テストされたマージは、メインブランチの観点からのフォワードマージでない場合、コミットをメインブランチにマージすると失敗する可能性があるためです。

結果として:

  • メインブランチへの人間のコミットを禁止します(可能な場合は自動的に行いますが、抜け穴がある場合、またはこれを実施することが技術的に実行可能でない場合は公式プロセスの一部としても)

    少なくとも、ルールが決まり次第、誰も意図せずに、または悪意なくそれを行わないようにすることができます。絶対にやろうとしないでください。

  • 次の中から選択する必要があります。

    • 単一のステージングブランチ。以前はビルドされておらず、テストもされていないマージが失敗すると、マージが成功します。

      少なくとも、どのマージが失敗したかを知って誰かに修正してもらえますが、ビルドとテストの結果について、その間のマージは(バージョン管理システムによって)簡単には追跡できません。

      ファイル注釈(または非難)を見ることができますが、ファイルの変更(構成など)により、予期しない場所でエラーが発生することがあります。ただし、これはかなりまれなイベントです。

    • 複数のステージングブランチ。競合しないマージがメインブランチに到達できるようにします。

      他のステージングブランチに競合しないマージの失敗がある場合でも。少なくとも、ある合併が別の合併による影響のある変更を予期していなかった場合は、トレーサビリティが少し改善されています。しかし、繰り返しますが、これは毎日または毎週心配するほどではありません。

      ほとんどの場合、競合しないマージを行うには、たとえば、チームごと、レイヤーごと、コンポーネント/プロジェクト/システム/ソリューション(名前を付けても)ごとにステージングブランチを適切に分割することが重要です。

      その間にメインブランチが別のマージに転送された場合は、再度マージする必要があります。うまくいけば、これは競合しないマージや、競合がほとんどない問題ではありません。

ゲートチェックインと比較して、ここでの利点は、メインブランチが先に進むことのみが許可され、メインブランチが機能することを保証することです。3番目のポイントは本質的な違いです。


しかし、作業ブランチを持つことのポイントは、(通常)安定したリリースを確実にすることではなく、同じコードで一緒に作業する開発者によって引き起こされるスラッシングを削減することです。
テラスティン14年

グローバルに分散した大きなチームで巨大なリポジトリを持っている場合は別です。たとえば、MicrosoftはWindowsで同様のより階層化されたアプローチを使用しています。
acelent 14年

2

私は「合格した単体テスト」がコードを提出するためのゲートになることを好みます。ただし、それを機能させるには、いくつかのものが必要です。

アーティファクトをキャッシュするビルドフレームワークが必要になります。

特定のアーティファクトで、(成功した)テスト実行からのテストステータスをキャッシュするテストフレームワークが必要になります。

こうすることで、単体テストに合格したチェックインが迅速になり(ソースからチェックイン前に開発者がテストをチェックしたときに作成されたアーティファクトへのクロスチェック)、失敗した単体テストのあるものがブロックされ、コンパイルとテストのサイクルは長いので、コミットする前にビルドをチェックするのを忘れてしまうと便利です。


1

プロジェクトと、「コミット」で実行される自動テストの範囲に依存すると言います。

チェックイントリガーで実行したいテストが本当に速い場合、または開発者のワークフローがそのようなチェックイン後に何らかの管理作業を強制する場合、それはあまり重要ではなく、開発者にチェックのみを強制する必要があると思います最も基本的なテストを絶対に実行するもので。(このようなトリガーに対して最も基本的なテストのみを実行すると想定しています。)

そして、スピード/ワークフローが許せば、テストに失敗した他の開発者に変更をプッシュしないことは良いことだと思います。

あなたは質問に「リモートブランチにコミット...」と書いていますが、これは(a)開発者が数分ごとに行うものではないため、小さな待機は非常に受け入れられるかもしれません、そして(b)その後このようなコミットは、コードの変更が他の開発者に影響を与える可能性があるため、追加のチェックが適切に行われる場合があります。

そのような操作を待っている間、「開発者が待機中に親指をひねるな」という他の回答に同意することができます。


1

トランクは実稼働に入る可能性があるため、壊れたコミットはtrunkで許可されません。そのため、トランクに入る前に通過する必要があるゲートウェイがあることを確認する必要があります。ただし、レポジトリでは、トランク上にない限り、コミットの破損はまったく問題ありません。

一方、リポジトリに変更をプッシュする前に開発者に待機/修正を要求することには、多くの欠点があります。

いくつかの例:

  • TDDでは、機能の実装を開始する前に、新しい機能の失敗したテストをコミットしてプッシュするのが一般的です
  • 失敗したテストをコミットしてプッシュすることでバグを報告する場合も同じです
  • 不完全なコードをプッシュすると、2人以上の人が簡単に並行して機能を操作できます
  • CIインフラストラクチャの検証には時間がかかりますが、開発者は待つ必要はありません
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.