検査における悪夢は偽陽性です。 「すべてのものは過ぎ去っていきます!すばらしい!"将来いつになるか分からないが、すべての地雷が一斉に爆発し、チームを地獄に吹き飛ばすまでは。
テストがサイレントに失敗する理由は数多くあります。
今日は、非常に基本的な理由の 1 つについてお話します。それは、どれがテストなのかわからないということです。
ほとんどの人は Go プロジェクトに途中から参加します。ほとんどの人は、実生活で言語を使用することで言語を学びます。
したがって、誰かが testify のようなテスト フレームワークを使用してプロジェクトをセットアップした場合、おそらく次のようなメソッドがテストであると考えるでしょう。
func (suite *ExampleTestSuite) TestExample() { suite.Equal(5, suite.VariableThatShouldStartAtFive) }
次に、TestAnotherCase のような別のメソッドを追加すると、それが機能することがわかります。あなたはテストとは何かについては十分に理解していると思います。
あなたが話している「テスト」は、Go パッケージが話しているテストと同じではない可能性があります。
組み込みのテスト パッケージから、テストは次の形式の関数です
func TestXxx(*testing.T)
もちろん、組み込みのテスト パッケージには機能が制限されているため、ほとんどのプロジェクトは testify/suite またはその他の同様のサードパーティ パッケージをテスト フレームワークとして使用しています。 testify/スイートの観点から見たテストとは何ですか?
「Test」で始まるメソッドを追加してテストを追加します
ほら、テストには 2 つの異なる定義があります。
嘲笑などのツールを使用する場合は、次の内容をお読みください
もう AssertExpectations メソッドの呼び出しを忘れることを心配する必要はありません…AssertExpectations メソッドはテストの最後に呼び出されるように登録されています
すごいですね! 「つまり、モックを作成するだけで済み、予期した動作が発生したときにパッケージが通知してくれるのです。
そこに罠があります。
テストの最後に嘲笑が言うとき、それは実際には testify/suite からの定義ではなく testing からの定義を意味します。
次のコードがある場合、TestA のモック セットアップが TestB で使用されているため、両方とも失敗するはずですが、TestA と TestB の両方が成功していることがわかります。
package mockandsubtest import ( "fmt" "testing" "github.com/stretchr/testify/suite" ) // Prod code type ExternalService interface { Work() } type Server struct { externalService ExternalService } func NewServer(externalService ExternalService) *Server { return &Server{ externalService: externalService, } } // Test code type ServerSuite struct { suite.Suite ExternalService *MockExternalService Server } func TestServerSuite(t *testing.T) { suite.Run(t, &ServerSuite{}) } // Run before all test cases func (s *ServerSuite) SetupSuite() { s.ExternalService = NewMockExternalService(s.T()) s.Server = Server{externalService: s.ExternalService} } // In this test, Work is set up to be called once but not called func (s *ServerSuite) TestA() { fmt.Println("TestA is running") s.ExternalService.EXPECT().Work().Times(1) } // In this test, Work is called once unexpectedly func (s *ServerSuite) TestB() { fmt.Println("TestB is running") s.Server.externalService.Work() }
上記のコードを実行した結果は次のとおりです
TestA is running TestB is running PASS
テストと嘲笑の観点からは、TestServerSuite のみがテストとみなされていることがわかりました。 TestA と TestB が testify/suite によって内部的に実行されていても、 AssertExpectations が TestServerSuite の最後に呼び出されるのはこのためです。
モッカリーの観点からは、s.ExternalService は TestServerSuite のライフサイクルで 1 回呼び出されることになっており、実際に 1 回呼び出されます。したがって、期待は満たされます。
testify/スイートとテストの間のギャップを埋めるには 2 つの方法があります。
最初の方法は、次のように各テスト メソッドの前に新しいモックを作成することです。
func (suite *ExampleTestSuite) TestExample() { suite.Equal(5, suite.VariableThatShouldStartAtFive) }
テスト ケースごとにサーバー インスタンスをセットアップするのにコストがかかりすぎるなど、さまざまな理由により、プロジェクトでは現実的ではない場合があります。その後、各テストの後に手動でアサートする他の方向を試すことができます。
2 つ目は、各テスト メソッドの最後に AssertExpectations の呼び出しを追加することです。たとえば、各テスト メソッドの後に実行される TearDownTest で AssertExpectations を呼び出します。
func TestXxx(*testing.T)
以上がGo に隠されたテストの落とし穴を明らかにする: 誤検知を回避するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。