2

モックとスタブを生成するために、リフレクションを使用して Go インターフェイスを実装したいと考えています。しかし、reflectパッケージを見ると、その方法がわかりません (おそらく不可能です)。

WriteHeader(404)例: FuncがResponseWriterで呼び出すことをテストします。

type ResponseWriterMock struct {                              //
  status int                                                  //
}                                                             // How to replace
func (*ResponseWriterMock) Header() Header {}                 // this block with 
func (*ResponseWriterMock) Write([]byte) (i int, e error) {}  // a reflectivly 
func (m *ResponseWriterMock) WriteHeader(status int) {        // generated mock? 
  m.status = status                                           //  
}                                                             //
responseWriterMock := new(ResponseWriterMock)

funcToTest(responseWriterMock)

if responseWriterMock.status != 404 {
    // report error
}

RhinoMocks (C#) では、次のように記述します。

var responseWriterMock = MockRepository.GenerateMock<ResponseWriter>();

funcToTest(responseWriterMock);

responseWriterMock.AssertWasCalled(rw => rw.WriteHeader(404));

リフレクションを使用して Go インターフェースを実装するにはどうすればよいですか?

補遺

今日は無理みたいです。

4

2 に答える 2

3

残念ながら、言語の静的な性質により、リフレクション パッケージは少し制限されており、実行時に動的オブジェクトを作成する方法はありません。それは決して不可能かもしれません。

いくつかの解決策を提案できます。すべて、設計時にスタブ/モックを作成する必要があります。

  1. モックを手動で作成します。

    人々がその道をたどり、コードベースが大きくなるとすぐに耐えられなくなるのを見てきました。

    一般に、アイデアは、インターフェイスを実装する構造を作成することです。各メソッドで、(呼び出しを追跡するために) いくつかのカウンターをインクリメントするコードを追加し、多くの場合、ハードコードされているか、構成として構造体に提供されている値を返します。

  2. testifyツールキットを使用します。

    これを書いている時点で、これはモッキングのサポートを提供する最も人気のあるプロジェクトのようです。ただし、プロジェクトは他の機能を提供するため、モッキング機能自体が原因でいいねがどれだけあるかは疑問です。

    私はこのツールキットを使用したことがなく、それが有効かどうかについて詳細な分析を提供することはできません.

    README を見ると、手動のモック化 (上記で説明) と非常によく似たアプローチを取っているようです。上にいくつかのヘルパー コードを提供しますが、偽のメソッドは手動で入力する必要があります。テストでのスタブは、文字列を介してメソッドを指定することによって行われます。これは、Go 言語の静的な性質に反しており、一部のユーザーにとっては問題になる可能性があります。

  3. Goの公式モックツールを使用します。

    このツールは、私が最後に書いて以来、人気を得ているようです。さらに、公式の Go プロジェクトと同様に、このツールは新しい Go 機能をすぐに採用することが期待できます。go モジュールのサポートは、他のツールが遅れている良い例です。

    モックには特定のアプローチが必要です。テスト コードの先頭で、テストの期待値を指定する必要があります。テストの最後に、フレームワークはすべての期待が満たされているかどうかをチェックします。予期しない呼び出しにより、フレームワークはテストに失敗します。

    Ginkgoのようなカスタム テスト フレームワークを使用している場合、きれいに統合するのは難しいかもしれません。私のプロジェクトでは、ギャップを埋めるヘルパー関数を作成しました。

    フェイク メソッドは生成されますが、生成されるアサーション メソッドと期待メソッドは型を取りinterface{}ます。これにより、フレームワークはより高度な引数マッチャーを提供できますが、正しい数の引数を正しい順序で渡す必要があることも意味します。

    私の経験では、このツールで作成されたテストは横が大きくなり、読みにくくなる傾向があります。プラス面として、彼らは物事をより徹底的にテストし、より表現力豊かです.

  4. 偽造ツールを使用します。

    このツールは、Cloud Foundry エコシステムで多く使用されており、実行可能なオプションであることが証明されています。

    特定のメソッドが呼び出された回数、メソッドの呼び出しに使用された引数を追跡し、カスタム実装でメソッド全体を偽造するか、返される結果値を指定することができます。

    良い選択となるのは、非常に露骨な偽物を生成することです。開発者は、メソッドを指定するために文字列名を使用する必要はなく、引数の順序と数を覚えておく必要もありません。生成されたヘルパー メソッドは、正しい型と順序の引数を使用して、元のメソッドによく似ています。


上記で提供したオプションの一部では、モックのソース コードを生成するためにコマンド ライン ツールを実行する必要があります。モックする必要のあるインターフェースの数が急速に増える可能性があるため、すべてを追跡するために使用できるクールなトリックがあります。

Goのgo:generate機能を利用して、すべてのスタブ/フェイクを簡単に生成できます。コマンド パラメーターを思い出したり、インターフェイスごとにツールを手動で実行したりする必要はありません。

go:generateインターフェイスを含むファイルに適切なコメントを追加するだけです。

モック

//go:generate mockgen -source person.go

type Person interface {
  Name() string
  Age() int
}

偽造者

//go:generate counterfeiter ./ Person

type Person interface {
  Name() string
  Age() int
}

その後、プロジェクトのルートでコマンドを実行するgo generate ./...と、すべてのスタブ/フェイクが再生成されます。複数の共同作業者がいるプロジェクトに取り組んでいる場合、これは命の恩人になる可能性があります。

于 2015-07-22T19:14:33.280 に答える
2

私の知る限り、この関連する質問の回答によると、実行時に新しい型を作成することはできません。

ユニバースでの新しい型の定義をサポートするgo-evalパッケージを試してみてください。

于 2012-10-18T12:00:01.443 に答える