Go言語でテストするための適切なパッケージの命名


102

私はGo内でいくつかの異なるテストパッケージの命名戦略を見てきましたが、それぞれの長所と短所が何であり、どれを使用する必要があるかを知りたいと思っていました。

戦略1:

ファイル名:github.com/user/myfunc.go

package myfunc

テストファイル名:github.com/user/myfunc_test.go

package myfunc

例については、bzip2を参照してください。

戦略2:

ファイル名:github.com/user/myfunc.go

package myfunc

テストファイル名:github.com/user/myfunc_test.go

package myfunc_test

import (
    "github.com/user/myfunc"
)

例については、ワイヤーを参照してください。

戦略3:

ファイル名:github.com/user/myfunc.go

package myfunc

テストファイル名:github.com/user/myfunc_test.go

package myfunc_test

import (
    . "myfunc"
)

例については、文字列を参照してください。

Go標準ライブラリは、戦略1と2を組み合わせて使用​​しているようです。3つのうちどれを使用すればよいですか?これはpackage *_test、パッケージのプライベートメソッドをテストできないことを意味するため、テストパッケージに追加するのは面倒ですが、気付かない隠れた利点があるのでしょうか。


9
この質問はさまざまな意見をもたらすだけですが、私は自分の意見を述べます。プライベートメソッドをテストする必要はありません。他の開発者が使用するパッケージのインターフェースをテストしたいとします。テストが失敗した場合は、プライベートメソッドを確認する必要があります。
ブレンデン2013年

2
[ワイヤー](github.com/btcsuite/btcd/blob/master/wire/msgtx_test.go戦略2)の例では、今も実際に戦略1の例である...
durp

回答:


130

リストした3つの戦略の根本的な違いは、テストコードがテスト対象のコードと同じパッケージにあるかどうかです。テストファイルを使用するpackage myfuncpackage myfunc_test、テストファイルで使用するかは、ホワイトボックステストを実行するか、ブラックボックステストを実行するかによって異なります。

プロジェクトで両方の方法を使用することに問題はありません。たとえば、あなたが持っている可能性がありmyfunc_whitebox_test.gomyfunx_blackbox_test.go

テストコードパッケージの比較

  • ブラックボックステスト:を使用しpackage myfunc_testます。これにより、エクスポートされた識別子のみが使用れるようになります。
  • ホワイトボックステスト:package myfuncエクスポートされていない識別子にアクセスできるように使用します。エクスポートされていない変数、関数、メソッドへのアクセスを必要とする単体テストに適しています。

問題にリストされている戦略の比較

  • 戦略1:ファイルがmyfunc_test.go使用するpackage myfunc—この場合、のテストコードは、この例のでmyfunc_test.goテストされるコードと同じパッケージに含まれます。myfunc.gomyfunc
  • 戦略2:ファイルがmyfunc_test.go使用するpackage myfunc_test—この場合、myfunc_test.go「別のパッケージとしてコンパイルされ、メインのテストバイナリでリンクおよび実行される」のテストコード。[ソース:test.goソースコードの58〜59行目]
  • 戦略3:ファイルmyfunc_test.goは使用しますpackage myfunc_testmyfunc、ドット表記を使用してインポートします—これは戦略2の変形ですが、ドット表記を使用してインポートしmyfuncます。

1
戦略1を使用すると_test.go、テスト対象のパッケージとは別のファイルも保持されることに注意してください(戦略2と同じ動作)。これはgithub.com/golang/go/issues/15315
Kevin Deenanauth

強力なパッケージ使用戦略3を見ましたが、何の意味があるのか​​理解できません。
PickBoy

1
パッケージをフォークして変更を加えたところ、テストではすべて、フォークされたパッケージの代わりに元のリポジトリをインポートしようとしています。戦略3では、「github.com/original/link」を「github.com/my/fork」に変更する必要はありません。これは単に「。」を参照しているだけだからです。代わりに。
nmarley

1
@KevinDeenanauthこれはちょうど私を驚かせた。テスト用のグローバルパッケージ変数を変更するを含む_test.go_testパッケージ名のを見つけたとき、私は落とし穴を見つけたと思いましたfunc init()。私は間違っていた。
Zyl

1
@nmarleyは.フォークの問題を解決しません。これは相対的なインポートではありません。識別子を「現在のパッケージに」インポートするだけです。
qaisjp

19

テストの範囲によって異なります。高レベルのテスト(統合、受け入れなど)は、エクスポートされたAPIを介してパッケージを使用していることを確認するために、おそらく別のパッケージに配置する必要があります。

テストする必要がある多くの内部構造を持つ大きなパッケージがある場合、テストには同じパッケージを使用します。しかし、それはあなたのテストが少しでもプライベートな状態にアクセスするための招待状ではありません。それは悪夢のリファクタリングになります。私が構造体を書いているとき、私はしばしばインターフェースを実装しています。テストから呼び出すのはこれらのインターフェースメソッドであり、すべてのヘルパーメソッド/関数が個別に呼び出されるわけではありません。


13

可能な限り、戦略1を使用する必要があります。foo_testインポートサイクルを回避するために特別なパッケージ名を使用できますが、ほとんどの場合、標準のライブラリを同じメカニズムでテストできます。たとえばstringstestingパッケージはに依存してstringsいるため、戦略1ではテストできません。すでに述べたように、戦略2または3では、パッケージのプライベートIDにアクセスできないため、必要でない限り、通常は使用しないことをお勧めします。


10
テストでプライベート識別子にアクセスできないのはなぜ美徳ではないのですか?
jub0bs

3
適切なテストプラクティスに従って、コードアーティファクトの内部実装の詳細はテストしません。息子をやっている、コードのにおいです
ヘラルドリマ

0

Golang CodeReviewCommentsimport .から追加したい重要なメモ:

このimport .フォームは、循環依存のために、テスト対象のパッケージの一部にすることができないテストで役立ちます。

package foo_test

import (
    "bar/testutil" // also imports "foo"
    . "foo"
)

この場合、テストファイルはfoo bar/testutilをインポートするを使用するため、パッケージfooに含めることはできません 。したがって、「インポート」を使用します。ファイルがパッケージfooの一部ではないように見せかけます。

この1つの場合を除いてimport .、プログラムでは使用しないでください。Quuxのような名前が現在のパッケージのトップレベルの識別子なのか、インポートされたパッケージのトップレベルの識別子なのかがはっきりしないため、プログラムが読みにくくなります。

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