如何编写 sort.Slice() 的测试?

huangapple go评论173阅读模式
英文:

How do you write a test for sort.Slice()?

问题

给定sort.Slice(array, func(int, int) bool)如何在传入的函数中使用数组,你会如何为匿名函数编写测试?

来自go文档中sort.Slice()的示例代码如下:

  1. package main
  2. import (
  3. "fmt"
  4. "sort"
  5. )
  6. func main() {
  7. people := []struct {
  8. Name string
  9. Age int
  10. }{
  11. {"Gopher", 7},
  12. {"Alice", 55},
  13. {"Vera", 24},
  14. {"Bob", 75},
  15. }
  16. sort.Slice(people, func(i, j int) bool { return people[i].Name < people[j].Name })
  17. fmt.Println("By name:", people)
  18. sort.Slice(people, func(i, j int) bool { return people[i].Age < people[j].Age })
  19. fmt.Println("By age:", people)
  20. }

如果将匿名函数拆分为两个单独的函数(例如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:

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;sort&quot;
  5. )
  6. func main() {
  7. people := []struct {
  8. Name string
  9. Age int
  10. }{
  11. {&quot;Gopher&quot;, 7},
  12. {&quot;Alice&quot;, 55},
  13. {&quot;Vera&quot;, 24},
  14. {&quot;Bob&quot;, 75},
  15. }
  16. sort.Slice(people, func(i, j int) bool { return people[i].Name &lt; people[j].Name })
  17. fmt.Println(&quot;By name:&quot;, people)
  18. sort.Slice(people, func(i, j int) bool { return people[i].Age &lt; people[j].Age })
  19. fmt.Println(&quot;By age:&quot;, people)
  20. }

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

将要测试的功能移动到一个命名函数中。测试该函数。

  1. type Person struct {
  2. Name string
  3. Age int
  4. }
  5. func personLessByName(people []Person, i, j int) bool {
  6. return people[i].Name < people[j].Name
  7. }
  8. func personLessByAge(people []Person, i, j int) bool {
  9. return people[i].Age < people[j].Age
  10. }

在调用sort.Slice时使用该函数:

  1. sort.Slice(people, func(i, j int) bool { return personLessByName(people, i, j) })
  2. sort.Slice(people, func(i, j int) bool { return personLessByAge(people, i, j) })

以下是一个测试示例:

  1. func TestComparePeople(t *testing.T) {
  2. cases := []struct {
  3. desc string
  4. a, b Person
  5. fn func([]Person, int, int) bool
  6. expected bool
  7. }{
  8. {"name a < b", Person{"bill", 10}, Person{"melinda", 20}, personLessByName, true},
  9. {"name a > b", Person{"melinda", 30}, Person{"bill", 20}, personLessByName, false},
  10. {"name a = b", Person{"melinda", 90}, Person{"melinda", 90}, personLessByName, false},
  11. {"age a < b", Person{"melinda", 10}, Person{"bill", 20}, personLessByAge, true},
  12. {"age a > b", Person{"melinda", 30}, Person{"bill", 20}, personLessByAge, false},
  13. {"age a = b", Person{"melinda", 90}, Person{"bill", 90}, personLessByAge, false},
  14. }
  15. for _, c := range cases {
  16. people := []Person{c.a, c.b}
  17. got := c.fn(people, 0, 1)
  18. if c.expected != got {
  19. t.Errorf("%s: expected %v, got %v", c.desc, c.expected, got)
  20. }
  21. }
  22. }
英文:

Move the functionality that you want to test to a named function. Test that function.

  1. type Person struct {
  2. Name string
  3. Age int
  4. }
  5. func personLessByName(people []Person, i, j int) bool {
  6. return people[i].Name &lt; people[j].Name
  7. }
  8. func personLessByAge(people []Person, i, j int) bool {
  9. return people[i].Age &lt; people[j].Age
  10. }

Use the function in the call to sort.Slice:

  1. sort.Slice(people, func(i, j int) bool { return personLessByName(people, i, j) })
  2. sort.Slice(people, func(i, j int) bool { return personLessByAge(people, i, j) })

Here'a test:

  1. func TestComparePeople(t *testing.T) {
  2. cases := []struct {
  3. desc string
  4. a, b Person
  5. fn func([]Person, int, int) bool
  6. expected bool
  7. }{
  8. {&quot;name a &lt; b&quot;, Person{&quot;bill&quot;, 10}, Person{&quot;melinda&quot;, 20}, personLessByName, true},
  9. {&quot;name a &gt; b&quot;, Person{&quot;melinda&quot;, 30}, Person{&quot;bill&quot;, 20}, personLessByName, false},
  10. {&quot;name a = b&quot;, Person{&quot;melinda&quot;, 90}, Person{&quot;melinda&quot;, 90}, personLessByName, false},
  11. {&quot;age a &lt; b&quot;, Person{&quot;melinda&quot;, 10}, Person{&quot;bill&quot;, 20}, personLessByAge, true},
  12. {&quot;age a &gt; b&quot;, Person{&quot;melinda&quot;, 30}, Person{&quot;bill&quot;, 20}, personLessByAge, false},
  13. {&quot;age a = b&quot;, Person{&quot;melinda&quot;, 90}, Person{&quot;bill&quot;, 90}, personLessByAge, false},
  14. }
  15. for _, c := range cases {
  16. people := []Person{c.a, c.b}
  17. got := c.fn(people, 0, 1)
  18. if c.expected != got {
  19. t.Errorf(&quot;%s: expected %v, got %v&quot;, c.desc, c.expected, got)
  20. }
  21. }
  22. }

答案2

得分: -1

在稍微尝试了一下之后,我写了这段代码。它使用一个工厂函数来创建方法,以便将切片包含在函数的闭包中。

我将它放在了一个 gist 中,以便轻松地进行测试:https://gist.github.com/docwhat/e3b13265d24471651e02f7d7a42e7d2c

  1. // main.go
  2. package main
  3. import (
  4. "fmt"
  5. "sort"
  6. )
  7. type Person struct {
  8. Name string
  9. Age int
  10. }
  11. func comparePeopleByName(people []Person) func(int, int) bool {
  12. return func(i, j int) bool {
  13. return people[i].Name < people[j].Name
  14. }
  15. }
  16. func comparePeopleByAge(people []Person) func(int, int) bool {
  17. return func(i, j int) bool {
  18. return people[i].Age < people[j].Age
  19. }
  20. }
  21. func main() {
  22. people := []Person{
  23. {"Gopher", 7},
  24. {"Alice", 55},
  25. {"Vera", 24},
  26. {"Bob", 75},
  27. }
  28. sort.Slice(people, comparePeopleByName(people))
  29. fmt.Println("按姓名排序:", people)
  30. sort.Slice(people, comparePeopleByAge(people))
  31. fmt.Println("按年龄排序:", people)
  32. }
  1. // main_test.go
  2. package main
  3. import "testing"
  4. func TestComparePeopleByName(t *testing.T) {
  5. testCases := []struct {
  6. desc string
  7. a, b Person
  8. expected bool
  9. }{
  10. {"a < b", Person{"bob", 1}, Person{"krabs", 2}, true},
  11. {"a > b", Person{"krabs", 1}, Person{"bob", 2}, false},
  12. {"a = a", Person{"plankton", 1}, Person{"plankton", 2}, false},
  13. }
  14. for _, testCase := range testCases {
  15. t.Run(testCase.desc, func(t *testing.T) {
  16. people := []Person{testCase.a, testCase.b}
  17. got := comparePeopleByName(people)(0, 1)
  18. if testCase.expected != got {
  19. t.Errorf("期望 %v,得到 %v", testCase.expected, got)
  20. }
  21. })
  22. }
  23. }
  24. func TestComparePeopleByAge(t *testing.T) {
  25. testCases := []struct {
  26. desc string
  27. a, b Person
  28. expected bool
  29. }{
  30. {"a < b", Person{"sandy", 10}, Person{"patrick", 20}, true},
  31. {"a > b", Person{"sandy", 30}, Person{"patrick", 20}, false},
  32. {"a = b", Person{"sandy", 90}, Person{"patrick", 90}, false},
  33. }
  34. for _, testCase := range testCases {
  35. t.Run(testCase.desc, func(t *testing.T) {
  36. people := []Person{testCase.a, testCase.b}
  37. got := comparePeopleByAge(people)(0, 1)
  38. if testCase.expected != got {
  39. t.Errorf("期望 %v,得到 %v", testCase.expected, got)
  40. }
  41. })
  42. }
  43. }
英文:

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

  1. // main.go
  2. package main
  3. import (
  4. &quot;fmt&quot;
  5. &quot;sort&quot;
  6. )
  7. type Person struct {
  8. Name string
  9. Age int
  10. }
  11. func comparePeopleByName(people []Person) func(int, int) bool {
  12. return func(i, j int) bool {
  13. return people[i].Name &lt; people[j].Name
  14. }
  15. }
  16. func comparePeopleByAge(people []Person) func(int, int) bool {
  17. return func(i, j int) bool {
  18. return people[i].Age &lt; people[j].Age
  19. }
  20. }
  21. func main() {
  22. people := []Person{
  23. {&quot;Gopher&quot;, 7},
  24. {&quot;Alice&quot;, 55},
  25. {&quot;Vera&quot;, 24},
  26. {&quot;Bob&quot;, 75},
  27. }
  28. sort.Slice(people, comparePeopleByName(people))
  29. fmt.Println(&quot;By name:&quot;, people)
  30. sort.Slice(people, comparePeopleByAge(people))
  31. fmt.Println(&quot;By age:&quot;, people)
  32. }
  1. // main_test.go
  2. package main
  3. import &quot;testing&quot;
  4. func TestComparePeopleByName(t *testing.T) {
  5. testCases := []struct {
  6. desc string
  7. a, b Person
  8. expected bool
  9. }{
  10. {&quot;a &lt; b&quot;, Person{&quot;bob&quot;, 1}, Person{&quot;krabs&quot;, 2}, true},
  11. {&quot;a &gt; b&quot;, Person{&quot;krabs&quot;, 1}, Person{&quot;bob&quot;, 2}, false},
  12. {&quot;a = a&quot;, Person{&quot;plankton&quot;, 1}, Person{&quot;plankton&quot;, 2}, false},
  13. }
  14. for _, testCase := range testCases {
  15. t.Run(testCase.desc, func(t *testing.T) {
  16. people := []Person{testCase.a, testCase.b}
  17. got := comparePeopleByName(people)(0, 1)
  18. if testCase.expected != got {
  19. t.Errorf(&quot;expected %v, got %v&quot;, testCase.expected, got)
  20. }
  21. })
  22. }
  23. }
  24. func TestComparePeopleByAge(t *testing.T) {
  25. testCases := []struct {
  26. desc string
  27. a, b Person
  28. expected bool
  29. }{
  30. {&quot;a &lt; b&quot;, Person{&quot;sandy&quot;, 10}, Person{&quot;patrick&quot;, 20}, true},
  31. {&quot;a &gt; b&quot;, Person{&quot;sandy&quot;, 30}, Person{&quot;patrick&quot;, 20}, false},
  32. {&quot;a = b&quot;, Person{&quot;sandy&quot;, 90}, Person{&quot;patrick&quot;, 90}, false},
  33. }
  34. for _, testCase := range testCases {
  35. t.Run(testCase.desc, func(t *testing.T) {
  36. people := []Person{testCase.a, testCase.b}
  37. got := comparePeopleByAge(people)(0, 1)
  38. if testCase.expected != got {
  39. t.Errorf(&quot;expected %v, got %v&quot;, testCase.expected, got)
  40. }
  41. })
  42. }
  43. }

huangapple
  • 本文由 发表于 2022年7月21日 02:15:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/73056418.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定