为了调用注册的路由,Application 类型实现 http.Handler 接口 。http.Handler 作为 Application 的内嵌结构体字段,因此 Application 可以调用 http.Handler 接口实现的ServeHTTP 函数
清单 8req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/list/%d/item", test.ListID), nil)if err != nil { t.Errorf("error creating request: %v", err)}w := httptest.NewRecorder()a.ServeHTTP(w, req)
回顾一下代码清单 5,构造 Application 是为了在测试中使用 。ServeHTTP 函数需要两个参数:http.ResponseWriter 和 http.Request 。http.NewRequest 构造 http.Request,httptest.NewRecorder 构造 http.ResponseRecorder——即 http.Response。
http.NewRecorder 函数的返回 ResponseRecorder 值实现了 ResponseWriter 接口 。调用路由请求后,ResponseRecorder 可以用来分析了 。其中最关键的字段 Code 和 Body,前者是该请求的实际响应码,后者是一个指向响应内容的 bytes.Buffer 类型的指针 。
译者注:这里的 http.ResponseWriter 和 http.Request 实现了 Golang 中常见的 Writer和 Reader 接口,即 输出 和 输入,在 http 请求中即 Response 和 Request 。清单 9
if want, got := http.StatusOK, w.Code; want != got { t.Errorf("expected status code: %v, got status code: %v", want, got)}
清单 9 中,实际的响应码和预期的响应码做对比 。如果不同,将调用 t.Errorf,它将输出失败原因 。清单 10
var items []item.Itemresp := web.Response{ Results: items,}if err := json.NewDecoder(w.Body).Decode(&resp); err != nil { t.Errorf("error decoding response body: %v", err)}if d := cmp.Diff(expectedItems, items); d != "" { t.Errorf("unexpected difference in response body:n%v", d)}
示例中使用自定义响应体 web.Response,使用 键为 results 的 JSON 字符串存储路由返回信息 。代码清单 10 中声明了一个 []item.Item 类型的变量 items,用于和预期值对比 。初始化 items 变量传递给 resp 的字段 results 。接下来,items 会随着解析路由响应体数据到 resp 中,从而包含响应体的数据 。google 的 go-cmp[4] 包可替代 reflect.DeepEqual,在对比 struct,map,slice 和 array 时更安全,更易用 。调用 cmp.Diff 对比清单 6 中定义的种子数据和实际响应体中返回的数据,如果不等,测试将失败,并且将差异输出到标准输出(stdout)中 。
测试技巧就测试而言,最好的建议是尽早测试,并且经常测试,而不是将测试放到开发之后考虑,而且测试应该推动、驱动应用程序的开发 。这就是“测试驱动开发(TDD)” 。通常情况下,没有随时测试代码 。在编写代码时,将测试的想法抛到脑后,自己(开发人员)默认编写的代码是可测试的 。代码单元(通常是一个函数)不管再小都能进行测试 。你的服务进行越多测试,未知的就越少,隐藏的副作用(bug)就越少 。
有了下面这些技巧,你的测试将洞察力,更易读,更快 。
表测试表测试是一种编写测试的方式,可以防止针对同一代码单元的不同可测试结果重复测试断言 。以下面的求和函数为例:
清单 11
// Add takes an indefinite amount of operands and adds them together, returning// the sum of the operation.func Add(operands ...int) int { var sum int for _, operand := range operands { sum += operand } return sum}
在测试中,我想确保函数可以处理以下情况:- 没有参数(operands),应返回 0 。
- 一个参数,直接返回参数值 。
- 两个参数,返回这两个数之和 。
- 三个参数,则返回这三个数之和 。
推荐阅读
- 索泰推出被动散热迷你主机:搭载十代 i3,双网口
- java枚举类型,为什么强烈推荐使用?看看它的7种场景方法
- 漏洞无处不在,3步教你暴力破解ssh服务
- 敬老爱老的优美句子有哪些?
- 淘宝店铺描述写什么 淘宝开店描述下你的店铺这怎么写
- 茶在手中是风景,你我都是彼此的小心柑
- 淘宝店铺销量突然下降是什么原因 为什么淘宝销量突然减少
- 茶礼潜规则你知道否,至心茶礼
- 红茶解暑秘招 让你轻松一夏
- 淘宝不实名认证 为什么会不符合淘宝认证的要求