使用Golang的gomock进行单元测试时遇到的问题

使用Golang的gomock进行单元测试时遇到的问题 我想在此文件中模拟 GetAd 方法,但遇到了错误 invalid memory address or nil pointer dereference [recovered],因为 GetAd 函数在应该返回模拟响应的地方被调用,而那里实际上执行了 HTTP 请求。有什么建议吗? 注意:mockgen 用于从接口构建模拟,gomock 用于模拟。

主文件:

type BroswerAdHandler struct {
	CustomerKey      string
	SiteID           string
	BrowserAdUsecase domain.BrowserAdUsecase
}

func (h BroswerAdHandler) GetBrowserAd(c echo.Context) error {
............
result, err := h.BrowserAdUsecase.GetAd(queryParam)
	if err != nil {
		c.JSON(http.StatusInternalServerError, echo.Map{"errorCode": "APIError", "description": 
      err.Error()})
	}

	return c.JSON(http.StatusOK, result)
}

测试文件:

func TestGetBrowserAd(t *testing.T) {
var mockRespose domain.Result
err := faker.FakeData(&mockRespose)
assert.NoError(t, err)

controller := gomock.NewController(t)
defer controller.Finish()

browserAsUsecase := mock_domain.NewMockBrowserAdUsecase(controller)
browserAsUsecase.EXPECT().GetAd(gomock.Any()).Return(mockRespose, nil)


e := echo.New()
req, err := http.NewRequest(http.MethodGet, "/browserAdCampaigns?deviceId=123&appVersion=123&sdkVersion=123&deviceType=android&deviceUserAgent=kjabjsd&advertisingId=jabsd", strings.NewReader(""))
assert.NoError(t, err)

rec := httptest.NewRecorder()
c := e.NewContext(req, rec)

a := browserAdHttp.BroswerAdHandler{CustomerKey: "someKey", SiteID: "someID", BrowserAdUsecase: usecase.BrowserAdUsecase{URL: "http://xyz.com"}}
err = a.GetBrowserAd(c)

if err != nil {
	t.Fail()
}

更多关于使用Golang的gomock进行单元测试时遇到的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于使用Golang的gomock进行单元测试时遇到的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


问题在于测试中创建 BroswerAdHandler 时,没有正确注入模拟对象。你创建了实际的 BrowserAdUsecase 结构体实例,而不是使用模拟对象,这导致 GetAd 方法执行了真实的 HTTP 请求。

以下是修正后的测试代码:

func TestGetBrowserAd(t *testing.T) {
    var mockResponse domain.Result
    err := faker.FakeData(&mockResponse)
    assert.NoError(t, err)

    controller := gomock.NewController(t)
    defer controller.Finish()

    // 创建模拟对象
    mockUsecase := mock_domain.NewMockBrowserAdUsecase(controller)
    mockUsecase.EXPECT().GetAd(gomock.Any()).Return(mockResponse, nil)

    e := echo.New()
    req, err := http.NewRequest(
        http.MethodGet, 
        "/browserAdCampaigns?deviceId=123&appVersion=123&sdkVersion=123&deviceType=android&deviceUserAgent=kjabjsd&advertisingId=jabsd", 
        strings.NewReader(""),
    )
    assert.NoError(t, err)

    rec := httptest.NewRecorder()
    c := e.NewContext(req, rec)

    // 关键修正:使用模拟对象而不是实际实现
    a := browserAdHttp.BroswerAdHandler{
        CustomerKey:      "someKey",
        SiteID:           "someID",
        BrowserAdUsecase: mockUsecase, // 注入模拟对象
    }
    
    err = a.GetBrowserAd(c)
    assert.NoError(t, err)
    
    // 验证响应
    assert.Equal(t, http.StatusOK, rec.Code)
    
    var actualResponse domain.Result
    err = json.Unmarshal(rec.Body.Bytes(), &actualResponse)
    assert.NoError(t, err)
    assert.Equal(t, mockResponse, actualResponse)
}

主要修正点:

  1. 将模拟对象 mockUsecase 注入到 BroswerAdHandlerBrowserAdUsecase 字段
  2. 移除了实际 BrowserAdUsecase 结构体的创建
  3. 添加了响应验证逻辑

确保你的 mock_domain 包是通过 mockgen 正确生成的:

mockgen -source=domain/browser_ad_usecase.go -destination=mocks/mock_domain/mock_browser_ad_usecase.go -package=mock_domain

这样修改后,GetAd 方法将调用模拟实现而不是执行实际的 HTTP 请求,从而避免 nil pointer dereference 错误。

回到顶部