GoLangで単体テストと統合テストを分離するための確立されたベストプラクティスはありますか(testify)?ユニットテスト(外部リソースに依存しないため非常に高速に実行される)と統合テスト(外部リソースに依存するため実行に時間がかかる)が混在しています。したがって、go test
と言ったときに統合テストを含めるかどうかを制御できるようにしたいと思います。
最も簡単な手法は、mainで-integrateフラグを定義することです。
var runIntegrationTests = flag.Bool("integration", false
, "Run the integration tests (in addition to the unit tests)")
そして、すべての統合テストの先頭にifステートメントを追加するには:
if !*runIntegrationTests {
this.T().Skip("To run this test, use: go test -integration")
}
これは私ができる最善ですか?私はtestifyのドキュメントを検索して、おそらく命名規則またはこれを実現する何かがあるかどうかを確認しましたが、何も見つかりませんでした。何か不足していますか?
@ Ainar-Gは、テストを分離するための優れたパターンをいくつか提案しています。
このSoundCloudのGoプラクティスのセット は、ビルドタグを使用することを推奨します( ビルドパッケージの「ビルドの制約」セクションで説明 )、実行するテストを選択します。
Integration_test.goを作成し、統合のビルドタグを付けます。サービスアドレスや接続文字列などの(グローバル)フラグを定義し、テストで使用します。
// +build integration var fooAddr = flag.String(...) func TestToo(t *testing.T) { f, err := foo.Connect(*fooAddr) // ... }
go testは、go buildと同様にビルドタグを取得するため、
go test -tags=integration
を呼び出すことができます。また、flag.Parseを呼び出すパッケージmainを合成するため、宣言されて表示されているフラグはすべて処理され、テストで使用できます。
同様のオプションとして、ビルド条件// +build !unit
を使用してデフォルトで統合テストを実行し、go test -tags=unit
を実行してオンデマンドで統合テストを無効にすることもできます。
@adamcコメント:
ビルドタグを使用しようとする他のユーザーにとって、// +build test
コメントがファイルの最初の行であり、コメントの後に空白行を含めることが重要です。そうでない場合、-tags
コマンドはディレクティブを無視します。
また、ビルドコメントで使用されるタグにはダッシュを使用できませんが、アンダースコアは使用できます。たとえば、// +build unit-tests
は機能しませんが、// +build unit_tests
は機能します。
考えられる解決策は3つあります。 1つは、単体テストに shortモード を使用することです。したがって、統合テストを実行するには、go test -short
を単体テストで使用し、-short
フラグを使用せずに使用します。標準ライブラリは、短いモードを使用して、長時間実行されるテストをスキップするか、より単純なデータを提供することでテストをより速く実行します。
2番目は、規則を使用して、テストをTestUnitFoo
またはTestIntegrationFoo
のいずれかで呼び出し、 -run
テストフラグ を使用して、実行するテストを示します。したがって、単体テストにはgo test -run 'Unit'
を使用し、統合テストにはgo test -run 'Integration'
を使用します。
3番目のオプションは、環境変数を使用し、テストセットアップで os.Getenv
を使用して取得することです。次に、単純なgo test
を単体テストに、FOO_TEST_INTEGRATION=true go test
を統合テストに使用します。
私は個人的には-short
ソリューションを好みます。それはよりシンプルで標準ライブラリで使用されているため、長期実行テストを事実上分離/簡素化する方法のようです。ただし、-run
およびos.Getenv
ソリューションは柔軟性が向上します(正規表現が-run
に関係するため、さらに注意が必要です)。
@ Ainar-Gの優れた答えに対する私のコメントを詳しく説明するために、過去1年間、-short
とIntegration
命名規則の組み合わせを使用して、両方の世界のベストを達成してきました。
以前、ビルドフラグにより、複数のファイル(services_test.go
、services_integration_test.go
など)が必要になりました。
代わりに、最初の2つが単体テストであり、最後に統合テストがある次の例をご覧ください。
package services
import "testing"
func TestServiceFunc(t *testing.T) {
t.Parallel()
...
}
func TestInvalidServiceFunc3(t *testing.T) {
t.Parallel()
...
}
func TestPostgresVersionIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
...
}
最後のテストには次の規則があることに注意してください。
Integration
を使用します。-short
フラグディレクティブの下で実行されているかどうかを確認します。基本的に、仕様は次のようになります。「すべてのテストを通常どおりに記述します。長時間実行されるテストまたは統合テストの場合、この命名規則に従い、-short
がピアにとって素晴らしいことを確認します。」
go test -v -short
これにより、次のような素敵なメッセージセットが提供されます。
=== RUN TestPostgresVersionIntegration
--- SKIP: TestPostgresVersionIntegration (0.00s)
service_test.go:138: skipping integration test
go test -run Integration
これは統合テストのみを実行します。本番環境のカナリア煙テストに役立ちます。
明らかに、このアプローチのマイナス面は、誰かがgo test
フラグなしで-short
を実行すると、デフォルトですべてのテスト(ユニットテストと統合テスト)が実行されることです。
実際には、プロジェクトがユニットテストと統合テストを行うのに十分な大きさである場合、go test -short
を使用するための簡単なディレクティブを持つことができるMakefile
を使用している可能性があります。または、それをREADME.md
ファイルに入れて、その日に呼び出します。
私は最近同じ解決策を見つけようとしていました。これらは私の基準でした:
前述のソリューション(カスタムフラグ、カスタムビルドタグ、環境変数)は上記のすべての基準を実際には満たしていないため、少し掘り下げて遊んだ後、このソリューションを思い付きました。
package main
import (
"flag"
"regexp"
"testing"
)
func TestIntegration(t *testing.T) {
if m := flag.Lookup("test.run").Value.String(); m == "" || !regexp.MustCompile(m).MatchString(t.Name()) {
t.Skip("skipping as execution was not requested explicitly using go test -run")
}
t.Parallel()
t.Run("HelloWorld", testHelloWorld)
t.Run("SayHello", testSayHello)
}
実装は簡単で最小限です。テストには簡単な規則が必要ですが、エラーが発生しにくいです。さらなる改善は、コードをヘルパー関数にエクスポートすることです。
プロジェクト内のすべてのパッケージでのみ統合テストを実行します。
go test -v ./... -run ^TestIntegration$
すべてのテストを実行します(regularおよび統合):
go test -v ./... -run .\*
regularテストのみを実行します:
go test -v ./...
このソリューションは、ツールを使用しなくても正常に機能しますが、Makefileまたは一部のエイリアスを使用するとユーザーが簡単になります。また、Goテストの実行をサポートするIDE=)に簡単に統合することもできます。
完全な例はここにあります: https://github.com/sagikazarmark/modern-go-application