web-dev-qa-db-ja.com

Gin-Gonicによる単体テスト

私のプロジェクトは、コントローラー、サービス、モデルの3つの主要コンポーネントに分かれています。 URIを介してルートが照会されると、コントローラーが呼び出され、コントローラーがサービスを呼び出してモデルと対話し、モデルはgormを介してデータベースと対話します。

コントローラーの単体テストを作成しようとしていますが、ジンレイヤーをモックしながらサービスレイヤーを適切にモックする方法を理解するのに苦労しています。モックされたginコンテキストを取得できますが、コントローラーメソッド内でサービスレイヤーをモックできません。以下は私のコードです:

resourceController.go

package controllers

import (
    "MyApi/models"
    "MyApi/services"
    "github.com/gin-gonic/gin"
    "net/http"
)

func GetResourceById(c *gin.Context) {
    id := c.Param("id")
    resource, err := services.GetResourceById(id)

    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"status": http.StatusBadRequest, "message": err})
        return
    } else if resource.ID == 0 {
        c.JSON(http.StatusNotFound, gin.H{"status": http.StatusNotFound, "message": "Resource with id:"+id+" does not exist"})
        return
    }

    c.JSON(http.StatusOK, gin.H{
        "id": resource.ID,
        "data1": resource.Data1,
        "data2": resource.Data2,
    })
}

C.JSONが適切なhttpステータスとその他のデータを返していることをテストしたいと思います。 id変数、err変数、c.JSON関数をモックする必要がありますが、テストでc.JSON関数を新しい関数に設定しようとすると、 「Cannot assign to c.JSON」というエラーが表示されます。以下はテストを書くための私の試みです:

resourceController_test.go

package controllers

import (
    "github.com/gin-gonic/gin"
    "github.com/stretchr/testify/assert"
    "net/http/httptest"
    "testing"
)

func TestGetResourceById(t *testing.T) {
    var status int
    var body interface{}
    c, _ := gin.CreateTestContext(httptest.NewRecorder())
    c.JSON = func(stat int, object interface{}) {
        status = stat
        body = object
    }
    GetResourceById(c)
    assert.Equal(t, 4, 4)
}

ユニットテストを適切に記述して、c.JSONが適切な値を返すかどうかをテストするにはどうすればよいですか?

2
Evan Bloemer

Goでタイプのメソッドを変更することはできません。コンパイル時に型を定義するパッケージによって定義され、変更できません。これはGoによる設計上の決定です。単にそれをしないでください。

_gin.Context.ResponseWriter_の呼び出しを含め、応答に書き込まれた内容を記録する_c.JSON_のモックとしてhttptest.NewRecorder()をすでに使用しています。ただし、_httptest.ReponseRecorder_の参照を保持して、後で確認する必要があります。マーシャリングされたJSONしかないので、コンテンツを確認するためにアンマーシャリングする必要があることに注意してください(GoマップとJSONオブジェクトの順序の両方が重要ではないため、マーシャリングされた文字列が等しいかどうかを確認するとエラーが発生しやすくなります)。

例えば、

_func TestGetResourceById(t *testing.T) {
    w := httptest.NewRecorder()
    c, _ := gin.CreateTestContext(w)
    GetResourceById(c)
    assert.Equal(t, 200, w.Code) // or what value you need it to be

    var got gin.H
    err := json.Unmarshal(&got, w.Body().Bytes())
    if err != nil {
        t.Fatal(err)
    }
    assert.Equal(t, want, got) // want is a gin.H that contains the wanted map.
}
_
2
leaf bebop