2017-12-04 4 views
0

私は基本的に多くのゲッター関数で構成される単純なパッケージを書いています。このパッケージ内の各ファイルは、サービスに対応します。たとえば、製品ファイルには、製品サービス/ db、注文ファイルからサービスなどに関連する関数が含まれています。各関数は、パラメータとしてdbリソースを基礎dbに、 SQLは、例えば、プロダクトID、名前、オーダーID。golangの関数を模擬する方法

// product.go 

package lib 

type Product struct { 
    ID int 
    Name string 
    Price float 
} 

func GetProductById(DB *sql.DB, ID int) (p Product, err error) { 
    q := "SELECT * FROM product WHERE id = " + ID 
    ... 
} 

func GetProductByName(DB *sql.DB, name string) (p Product, err error) { 
    ... 
} 

// order.go 

package lib 

type Order struct { 
    ID int 
    Date string 
    Items []items 
} 

func GetOrderById(DB *sql.DB, ID int) (o Order, err error) { 
    ... 
} 

問題は、私は私のメインのパッケージから、これらの機能を模擬することはできませんよということである:各関数は、構造体(例えば注文、製品)、またはエラーを返します。私が本当にやりたいことは、パッケージを書き直すことです。だから何とか関数に代わって型に渡すことができます。しかし、私はこれを行う方法がわかりません。特に関数が異なる入力パラメータをとり、異なる構造体を返す場合は特にありません。これを行う方法はありますか?

答えて

2

では、具体的な型のメソッド宣言と同じように、関数宣言をモックすることはできません。モックできません。例えば

func F() 

func (T) M() 

FMはゴーでmockableではありません。

ただし、変数、構造体のフィールド、または他の関数に渡されるパラメータのいずれでも、関数値をモックできます。例えば

var Fn = func() { ... } 

type S struct { 
    Fn func() 
} 

func F(Fn func()) 

Fnすべての3つのケースではmockableです。


行くにモックができ、他のもの、そしてほとんどの時間れる好ましい選択肢は、interfaceです。例えば

:今ProductRepositoryに依存したコードのどの部分がタイプProductStoreあなたが「通常モード」にしているの価値とあなたがしているタイプProductRepositoryMockの値を渡すことができ

type ProductRepository interface { 
    GetProductById(DB *sql.DB, ID int) (p Product, err error) 
} 

// the real implementater of the interface 
type ProductStore struct{} 

func (ProductStore) GetProductById(DB *sql.DB, ID int) (p Product, err error) { 
    q := "SELECT * FROM product WHERE id = " + ID 
    // ... 
} 

// the mock implementer 
type ProductRepositoryMock struct {} 

func (ProductRepositoryMock) GetProductById(DB *sql.DB, ID int) (p Product, err error) { 
    // ... 
} 

テスト。


あなたはほとんど unchagedあなたの機能を維持することを可能にするinterface Sを使用して別のオプションは、タイプがあなたの関数に渡されるように、そのインターフェイスタイプを使用し、その後*sql.DBの方法を模倣するインタフェースを定義することで、そのインタフェースのモックバージョンを実装し、それをテスト中に使用してください。例えば

type DBIface interface { 
    Query(query string, args ...interface{}) (*sql.Rows, error) 
    // ... 
    // It's enough to implement only those methods that 
    // the functions that depend on DBIface actually use. 
    // If none of your functions ever calls SetConnMaxLifetime 
    // you don't need to declare that method on the DBIface type. 
} 

type DBMock struct {} 

func (DBMock) Query(query string, args ...interface{}) (*sql.Rows, error) { 
    // ... 
} 

func GetProductByName(DB DBIface, name string) (p Product, err error) { 
    ... 
} 

DBパラメータGetProductByNameになりましmockableです。

関連する問題