使用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)
}
主要修正点:
- 将模拟对象
mockUsecase注入到BroswerAdHandler的BrowserAdUsecase字段 - 移除了实际
BrowserAdUsecase结构体的创建 - 添加了响应验证逻辑
确保你的 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 错误。

