Golang单元测试 | 测试经理质疑我不会自测?

2513 篇文章 2 订阅
2350 篇文章 14 订阅

软件测试面试刷题,这个小程序(永久刷题),靠它可以快速找到工作!https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502icon-default.png?t=N7T8https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502

测试驱动开发(Test-Driven Development,简称TDD)是一种软件开发的理念,尤其在后端开发中广泛应用,其核心思想是在实际编写任何业务逻辑代码之前,先编写测试用例

单元测试:针对每一个方法进行的测试,单独验证每一个方法的正确性。

集成测试:多个组件合并在一起的测试,验证各个方法、组件之间配合无误。

所以我们要先搞单元测试,单元测试初步验证之后,再集成测试。而单元测试和集成测试是要求开发人员自测的,不是测试的task(狗头保命)。【本文讲单元测试(以测 Handler 层的方法为例),后续会更新集成测试】

二、Table Driven模式

Go 里面,惯常的组织测试的方式,都是用 Table Driven 。其组织结构如下图,共三部分:1)定义测试用例 2)具体测试用例 3)执行测试用例

你把测试用例定义看做是列名,每一个测试用例就是一行数据,就能理解 Table Driven 这个含义了。

三、mock

单元测试不需要再构造 UserHandler 所依赖的 Service (如 UserServiceCodeService),而是用 mock 工具生成测试用的模拟的 UserServiceCodeService

mock 共两部分:

  1. mockgen:命令行工具。安装:go install go.uber.org/mock/mockgen@latest
  2. 测试中使用的控制 mock 对象的包。安装: https://github.com/uber-go/mock

四、测试Handler

1)为UserServiceCodeService 提供 mock 实现,执行如下命令,生成下图的 mock 文件

mockgen `-source=./webook/internal/service/article.go `-package=svcmocks `-destination=./webook/internal/service/mocks/article.mock.go 

image.png

test文件的实现:

package web

import (
    "bytes"
    "encoding/json"
    "errors"
    "github.com/gin-gonic/gin"
    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/require"
    "go.uber.org/mock/gomock"
    "net/http"
    "net/http/httptest"
    "refactor-webook/webook/internal/domain"
    "refactor-webook/webook/internal/service"
    svcmocks "refactor-webook/webook/internal/service/mocks"
    ijwt "refactor-webook/webook/internal/web/jwt"
    "testing"
)

func TestUserHandler_SignUp(t *testing.T) {
    testCases := []struct {
       name string
       mock func(ctrl *gomock.Controller) (service.UserService, service.CodeService, ijwt.Handler)
       // 预期中的输入
       reqBuilder func(t *testing.T) *http.Request
       // 预期中的输出
       wantCode int
       wantBody Result
    }{
       // 定义测试用例
       // note 先测试正常的流程(最长的流程),再考虑异常流程
       {
          name: "注册成功",
          mock: func(ctrl *gomock.Controller) (service.UserService, service.CodeService, ijwt.Handler) {
             userSvc := svcmocks.NewMockUserService(ctrl)
             userSvc.EXPECT().SignUp(gomock.Any(), domain.User{
                Email:    "123@qq.com",
                Password: "hello!123",
             }).Return(nil)
             // note CodeSvc没有用到的话,也可以直接写nil
             // return userSvc, nil
             codeSvc := svcmocks.NewMockCodeService(ctrl)
             return userSvc, codeSvc, nil
          },
          reqBuilder: func(t *testing.T) *http.Request {
             req, err := http.NewRequest(http.MethodPost, "/users/signup", bytes.NewReader(
                []byte(`{"email": "123@qq.com", "password": "hello!123", "confirmPassword":"hello!123"}`)))
             // note 易漏:为req的header添加content-type(因为Bind方法)
             req.Header.Set("Content-Type", "application/json")
             assert.NoError(t, err)
             return req
          },
          wantCode: http.StatusOK,
          wantBody: Result{
             Msg: "注册成功",
          },
       },
   }
    for _, tc := range testCases {
        t.Run(tc.name, func(t *testing.T) {
           // 1. 构造ctrl
           ctrl := gomock.NewController(t)
           defer ctrl.Finish()
           // 2. mock出来需要的svc
           userSvc, codeSvc, jwtHdl := tc.mock(ctrl)
           // 3. 构造hdl
           hdl := NewUserHandler(userSvc, codeSvc, jwtHdl)
           // 4.
           // 准备服务器和注册路由
           server := gin.Default()
           hdl.RegisterRoutes(server)
           // 准备请求和响应
           req := tc.reqBuilder(t)
           recorder := httptest.NewRecorder()

           // 本地接收http请求
           server.ServeHTTP(recorder, req)

           // 断言结果
           assert.Equal(t, tc.wantCode, recorder.Code)
           // 对res反序列化
           var res Result
           err := json.NewDecoder(recorder.Body).Decode(&res)
           assert.NoError(t, err)
           assert.Equal(t, tc.wantBody, res)
        })
    }
}

五、总结

  1. 测试 Handler 的难点在于“执行测试用例”中的 构造请求和响应
  2. 依赖注入和面向接口编程可以方便执行单元测试。
  3. 测试用例先写正常分支(执行路径最长的分支),然后再写异常分支,要尽量涵盖所有可能的分支。

最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】

​​​软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

在这里插入图片描述

在这里插入图片描述

  • 25
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值