英文:
How do you write a test for sort.Slice()?
问题
给定sort.Slice(array, func(int, int) bool)
如何在传入的函数中使用数组,你会如何为匿名函数编写测试?
package main
import (
"fmt"
"sort"
)
func main() {
people := []struct {
Name string
Age int
}{
{"Gopher", 7},
{"Alice", 55},
{"Vera", 24},
{"Bob", 75},
}
sort.Slice(people, func(i, j int) bool { return people[i].Name < people[j].Name })
fmt.Println("By name:", people)
sort.Slice(people, func(i, j int) bool { return people[i].Age < people[j].Age })
fmt.Println("By age:", people)
}
如果将匿名函数拆分为两个单独的函数(例如comparePeopleByName(i, j int)
和comparePeopleByAge(i, j, int)
),你会如何测试它们?
将函数与闭包绑定在一起似乎是一个奇怪的想法。
注意:我认为测试sort.Slice()
本身是不好的做法;它是语言自带的,不应该(需要?)进行测试。
英文:
Given the how sort.Slice(array, func(int, int) bool)
uses the array in the passed in function, how would you write a test for the anonymous function?
The example code from the go documentation for sort.Slice()
is:
package main
import (
"fmt"
"sort"
)
func main() {
people := []struct {
Name string
Age int
}{
{"Gopher", 7},
{"Alice", 55},
{"Vera", 24},
{"Bob", 75},
}
sort.Slice(people, func(i, j int) bool { return people[i].Name < people[j].Name })
fmt.Println("By name:", people)
sort.Slice(people, func(i, j int) bool { return people[i].Age < people[j].Age })
fmt.Println("By age:", people)
}
If you broke out the anonymous functions into two separate functions (e.g., comparePeopleByName(i, j int)
and comparePeopleByAge(i, j, int)
) how would you test them?
It seems like such a weird idea to tie the function to the closure.
Note: I'd consider it bad form to test sort.Slice()
itself; it ships with the language and shouldn't (need to?) be tested.
答案1
得分: 4
将要测试的功能移动到一个命名函数中。测试该函数。
type Person struct {
Name string
Age int
}
func personLessByName(people []Person, i, j int) bool {
return people[i].Name < people[j].Name
}
func personLessByAge(people []Person, i, j int) bool {
return people[i].Age < people[j].Age
}
在调用sort.Slice
时使用该函数:
sort.Slice(people, func(i, j int) bool { return personLessByName(people, i, j) })
sort.Slice(people, func(i, j int) bool { return personLessByAge(people, i, j) })
以下是一个测试示例:
func TestComparePeople(t *testing.T) {
cases := []struct {
desc string
a, b Person
fn func([]Person, int, int) bool
expected bool
}{
{"name a < b", Person{"bill", 10}, Person{"melinda", 20}, personLessByName, true},
{"name a > b", Person{"melinda", 30}, Person{"bill", 20}, personLessByName, false},
{"name a = b", Person{"melinda", 90}, Person{"melinda", 90}, personLessByName, false},
{"age a < b", Person{"melinda", 10}, Person{"bill", 20}, personLessByAge, true},
{"age a > b", Person{"melinda", 30}, Person{"bill", 20}, personLessByAge, false},
{"age a = b", Person{"melinda", 90}, Person{"bill", 90}, personLessByAge, false},
}
for _, c := range cases {
people := []Person{c.a, c.b}
got := c.fn(people, 0, 1)
if c.expected != got {
t.Errorf("%s: expected %v, got %v", c.desc, c.expected, got)
}
}
}
英文:
Move the functionality that you want to test to a named function. Test that function.
type Person struct {
Name string
Age int
}
func personLessByName(people []Person, i, j int) bool {
return people[i].Name < people[j].Name
}
func personLessByAge(people []Person, i, j int) bool {
return people[i].Age < people[j].Age
}
Use the function in the call to sort.Slice:
sort.Slice(people, func(i, j int) bool { return personLessByName(people, i, j) })
sort.Slice(people, func(i, j int) bool { return personLessByAge(people, i, j) })
Here'a test:
func TestComparePeople(t *testing.T) {
cases := []struct {
desc string
a, b Person
fn func([]Person, int, int) bool
expected bool
}{
{"name a < b", Person{"bill", 10}, Person{"melinda", 20}, personLessByName, true},
{"name a > b", Person{"melinda", 30}, Person{"bill", 20}, personLessByName, false},
{"name a = b", Person{"melinda", 90}, Person{"melinda", 90}, personLessByName, false},
{"age a < b", Person{"melinda", 10}, Person{"bill", 20}, personLessByAge, true},
{"age a > b", Person{"melinda", 30}, Person{"bill", 20}, personLessByAge, false},
{"age a = b", Person{"melinda", 90}, Person{"bill", 90}, personLessByAge, false},
}
for _, c := range cases {
people := []Person{c.a, c.b}
got := c.fn(people, 0, 1)
if c.expected != got {
t.Errorf("%s: expected %v, got %v", c.desc, c.expected, got)
}
}
}
答案2
得分: -1
在稍微尝试了一下之后,我写了这段代码。它使用一个工厂函数来创建方法,以便将切片包含在函数的闭包中。
我将它放在了一个 gist 中,以便轻松地进行测试:https://gist.github.com/docwhat/e3b13265d24471651e02f7d7a42e7d2c
// main.go
package main
import (
"fmt"
"sort"
)
type Person struct {
Name string
Age int
}
func comparePeopleByName(people []Person) func(int, int) bool {
return func(i, j int) bool {
return people[i].Name < people[j].Name
}
}
func comparePeopleByAge(people []Person) func(int, int) bool {
return func(i, j int) bool {
return people[i].Age < people[j].Age
}
}
func main() {
people := []Person{
{"Gopher", 7},
{"Alice", 55},
{"Vera", 24},
{"Bob", 75},
}
sort.Slice(people, comparePeopleByName(people))
fmt.Println("按姓名排序:", people)
sort.Slice(people, comparePeopleByAge(people))
fmt.Println("按年龄排序:", people)
}
// main_test.go
package main
import "testing"
func TestComparePeopleByName(t *testing.T) {
testCases := []struct {
desc string
a, b Person
expected bool
}{
{"a < b", Person{"bob", 1}, Person{"krabs", 2}, true},
{"a > b", Person{"krabs", 1}, Person{"bob", 2}, false},
{"a = a", Person{"plankton", 1}, Person{"plankton", 2}, false},
}
for _, testCase := range testCases {
t.Run(testCase.desc, func(t *testing.T) {
people := []Person{testCase.a, testCase.b}
got := comparePeopleByName(people)(0, 1)
if testCase.expected != got {
t.Errorf("期望 %v,得到 %v", testCase.expected, got)
}
})
}
}
func TestComparePeopleByAge(t *testing.T) {
testCases := []struct {
desc string
a, b Person
expected bool
}{
{"a < b", Person{"sandy", 10}, Person{"patrick", 20}, true},
{"a > b", Person{"sandy", 30}, Person{"patrick", 20}, false},
{"a = b", Person{"sandy", 90}, Person{"patrick", 90}, false},
}
for _, testCase := range testCases {
t.Run(testCase.desc, func(t *testing.T) {
people := []Person{testCase.a, testCase.b}
got := comparePeopleByAge(people)(0, 1)
if testCase.expected != got {
t.Errorf("期望 %v,得到 %v", testCase.expected, got)
}
})
}
}
英文:
After messing around a little, I wrote this bit of code. It uses a factory to create the method so that the slice is contained in the closure for the function.
I stuck it in a gist for easy playing around with: https://gist.github.com/docwhat/e3b13265d24471651e02f7d7a42e7d2c
// main.go
package main
import (
"fmt"
"sort"
)
type Person struct {
Name string
Age int
}
func comparePeopleByName(people []Person) func(int, int) bool {
return func(i, j int) bool {
return people[i].Name < people[j].Name
}
}
func comparePeopleByAge(people []Person) func(int, int) bool {
return func(i, j int) bool {
return people[i].Age < people[j].Age
}
}
func main() {
people := []Person{
{"Gopher", 7},
{"Alice", 55},
{"Vera", 24},
{"Bob", 75},
}
sort.Slice(people, comparePeopleByName(people))
fmt.Println("By name:", people)
sort.Slice(people, comparePeopleByAge(people))
fmt.Println("By age:", people)
}
// main_test.go
package main
import "testing"
func TestComparePeopleByName(t *testing.T) {
testCases := []struct {
desc string
a, b Person
expected bool
}{
{"a < b", Person{"bob", 1}, Person{"krabs", 2}, true},
{"a > b", Person{"krabs", 1}, Person{"bob", 2}, false},
{"a = a", Person{"plankton", 1}, Person{"plankton", 2}, false},
}
for _, testCase := range testCases {
t.Run(testCase.desc, func(t *testing.T) {
people := []Person{testCase.a, testCase.b}
got := comparePeopleByName(people)(0, 1)
if testCase.expected != got {
t.Errorf("expected %v, got %v", testCase.expected, got)
}
})
}
}
func TestComparePeopleByAge(t *testing.T) {
testCases := []struct {
desc string
a, b Person
expected bool
}{
{"a < b", Person{"sandy", 10}, Person{"patrick", 20}, true},
{"a > b", Person{"sandy", 30}, Person{"patrick", 20}, false},
{"a = b", Person{"sandy", 90}, Person{"patrick", 90}, false},
}
for _, testCase := range testCases {
t.Run(testCase.desc, func(t *testing.T) {
people := []Person{testCase.a, testCase.b}
got := comparePeopleByAge(people)(0, 1)
if testCase.expected != got {
t.Errorf("expected %v, got %v", testCase.expected, got)
}
})
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论