[英]What's the most idiomatic way of testing functions with HTTP requests in Go?
[英]What is the idiomatic way to test wrapper functions in Golang?
这并不罕见,当我们有一个带有很多参数的 function 时,创建一些使用带有预定义参数的通用 function 的伴随函数。 这是定义参数默认值的通常替代方法,Go 不允许这样做。
一个非常简单的示例是创建一个SquareArea
function,它使用更通用的RectangleArea
function。
func SquareArea(side int) int {
return RectangleArea(side, side)
}
func RectangleArea(width int, length int) int {
if width < 0 || length < 0 {
return 0
}
return width * length
}
对于这些功能,可以创建(有点)表测试
func TestSquareArea(t *testing.T) {
tests := []struct {
side int
expected int
}{
{side: -1, expected: 0},
{side: 0, expected: 0},
{side: 1, expected: 1},
{side: 2, expected: 4},
{side: 100, expected: 10000},
}
for idx, test := range tests {
if result := SquareArea(test.side); test.expected != result {
t.Errorf("test #%d expected != result (%d!=%d)", idx, test.expected, result)
}
}
}
func TestRectangleArea(t *testing.T) {
tests := []struct {
width int
length int
expected int
}{
{width: -1, length: -1, expected: 0},
{width: -1, length: 1, expected: 0},
{width: 1, length: -1, expected: 0},
{width: 2, length: 1, expected: 2},
{width: 1, length: 2, expected: 2},
{width: 3, length: 2, expected: 6},
{width: 2, length: 3, expected: 6},
{width: 10, length: 100, expected: 1000},
{width: 100, length: 10, expected: 1000},
}
for idx, test := range tests {
if result := RectangleArea(test.width, test.length); test.expected != result {
t.Errorf("test #%d expected != result (%d!=%d)", idx, test.expected, result)
}
}
}
这是正确的方法吗?
对于更复杂的功能和更多的配套功能,这种方法似乎会创建大量测试,同时实质上会多次测试相同的底层代码(即RectangleArea
)。
我觉得测试SquareArea
应该只确保使用正确的参数调用RectangleArea
。
这种代码方法(同时具有RectangleArea
和SquareArea
功能)在 Golang 中是惯用的吗? 在 Golang 上还有其他方法吗?
使用像 Python 这样的语言,我会模拟RectangleArea
function。
为了模仿这一点,我会做类似的事情:
var rectangleAreaFunction = RectangleArea
func SquareArea(side int) int {
return rectangleAreaFunction(side, side)
}
func RectangleArea(width int, length int) int {
if width < 0 || length < 0 {
return 0
}
return width * length
}
通过测试:
func TestSquareArea(t *testing.T) {
call:= ""
mock:= func(width int, length int) int {
call = fmt.Sprintf("func(%d,%d)", width, length)
return 0
}
rectangleAreaFunction = mock
tests := []struct {
side int
expected string
}{
{side: -1, expected: "func(-1,-1)"},
{side: 0, expected: "func(0,0)"},
{side: 1, expected: "func(1,1)"},
{side: 2, expected: "func(2,2)"},
{side: 100, expected: "func(100,100)"},
}
for idx, test := range tests {
call = ""
SquareArea(test.side)
if test.expected != call {
t.Errorf("test #%d expected != call (%s!=%s)", idx, test.expected, call)
}
}
}
func TestRectangleArea(t *testing.T) {
tests := []struct {
width int
length int
expected int
}{
{width: -1, length: -1, expected: 0},
{width: -1, length: 1, expected: 0},
{width: 1, length: -1, expected: 0},
{width: 2, length: 1, expected: 2},
{width: 1, length: 2, expected: 2},
{width: 3, length: 2, expected: 6},
{width: 2, length: 3, expected: 6},
{width: 10, length: 100, expected: 1000},
{width: 100, length: 10, expected: 1000},
}
for idx, test := range tests {
if result := RectangleArea(test.width, test.length); test.expected != result {
t.Errorf("test #%d expected != result (%d!=%d)", idx, test.expected, result)
}
}
}
但是似乎使用变量来保存实际的 function 来进行测试是不好的。
这种情况的另一个例子是通过第一次分类 function 处理 http 请求方法时:
func Triage(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
// some other common code like adding some context
*r = *(r.WithContext(context.WithValue(r.Context(), "key", "value")))
switch r.Method {
case POST:
triagePost(w, r)
default:
triageGet(w, r)
}
}
func triagePost(w http.ResponseWriter, r *http.Request) {
// some code
}
func triageGet(w http.ResponseWriter, r *http.Request) {
// some code
}
对这 3 个功能的完整测试将有很多无用的重复将Triage
function 的测试限制为:
r.Method
正确调用了正确的 function( triagePost
或triageGet
)将在测试实际行为时防止此类重复。
或者在 Golang 中拥有这种类型的代码(分类功能)是完全不正确的?
Go尽量避免mocking。 让我们尝试遵循惯用的方法(测试真实代码),看看它能带给我们多远。
Function SquareArea 使用相同的两个参数值调用 RectangleArea。 测试 SquareArea 并不关心 RectangleArea 的正确性。
SquareArea 的单个测试用例将提供 100% 的测试覆盖率,甚至不需要表驱动测试。
如果担心在给定两个相同值的参数时测试 RectangleArea 的正确性,则应将此测试用例直接添加到 RectangleArea 的表驱动测试中。
当然,如果 SquareArea 更复杂,那么我们将需要一个表驱动测试。 但在这种情况下,我们也必须关注 SquareArea 的作用,而不是RectangleArea 的作用。
换句话说,在决定如何测试 function(或任何实际的东西)时,我发现以下方法有助于减少疑虑:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.