测试 Golang 的 Goroutine

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

Test Golang Goroutine

问题

我一直在搜索,但到目前为止,只找到了由Ariejan de Vroom在这里写的类似文章。

我想知道是否可以将goroutine引入单元测试中,以便可以精确地计算并发的goroutine数量,并告诉我它们是否以我所述的数量正确地生成了goroutine。

我有以下示例代码:

  1. import (
  2. "testing"
  3. "github.com/stretchr/testify/assert"
  4. )
  5. func createList(job int, done chan bool) {
  6. time.Sleep(500)
  7. // do something
  8. time.Sleep(500)
  9. done <- true
  10. return
  11. }
  12. func TestNewList(t *testing.T) {
  13. list := NewList()
  14. if assert.NotNil(t, list) {
  15. const numGoRoutines = 16
  16. jobs := make(chan int, numGoRoutines)
  17. done := make(chan bool, 1)
  18. for j := 1; j <= numGoRoutines; j++ {
  19. jobs <- j
  20. go createList(j, done)
  21. fmt.Println("sent job", j)
  22. }
  23. close(jobs)
  24. fmt.Println("sent all jobs")
  25. <-done
  26. }
  27. }
英文:

I've been searching around, but so far only gone similar article written here by Ariejan de Vroom.

I would like to know if I can bring goroutine into unit testing such that it can precisely count the concurrent # of goroutines is running and can tell me if they are correctly spawned goroutine in the number I have stated.

I have the following code for example..

  1. import (
  2. &quot;testing&quot;
  3. &quot;github.com/stretchr/testify/assert&quot;
  4. )
  5. func createList(job int, done chan bool) {
  6. time.Sleep(500)
  7. // do something
  8. time.Sleep(500)
  9. done &lt;- true
  10. return
  11. }
  12. func TestNewList(t *testing.T) {
  13. list := NewList()
  14. if assert.NotNil(t, list) {
  15. const numGoRoutines = 16
  16. jobs := make(chan int, numGoRoutines)
  17. done := make(chan bool, 1)
  18. for j := 1; j &lt;= numGoRoutines; j++ {
  19. jobs &lt;- j
  20. go createList(j, done)
  21. fmt.Println(&quot;sent job&quot;, j)
  22. }
  23. close(jobs)
  24. fmt.Println(&quot;sent all jobs&quot;)
  25. &lt;-done
  26. }

答案1

得分: 1

根据我的理解,你希望限制同时运行的例程数量,并验证其是否正常工作。我建议编写一个函数,该函数将接受一个例程作为参数,并使用模拟例程对其进行测试。

以下是一个示例,spawn 函数会同时运行 fn 例程 count 次,但最多同时运行 limit 个例程。我将其包装在主函数中以在 playground 中运行,但你可以在测试方法中使用相同的方法。

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. )
  7. func spawn(fn func(), count int, limit int) {
  8. limiter := make(chan bool, limit)
  9. spawned := func() {
  10. defer func() { <-limiter }()
  11. fn()
  12. }
  13. for i := 0; i < count; i++ {
  14. limiter <- true
  15. go spawned()
  16. }
  17. }
  18. func main() {
  19. count := 10
  20. limit := 3
  21. var wg sync.WaitGroup
  22. wg.Add(count)
  23. concurrentCount := 0
  24. failed := false
  25. var mock = func() {
  26. defer func() {
  27. wg.Done()
  28. concurrentCount--
  29. }()
  30. concurrentCount++
  31. if concurrentCount > limit {
  32. failed = true // test could be failed here without waiting all routines finish
  33. }
  34. time.Sleep(100)
  35. }
  36. spawn(mock, count, limit)
  37. wg.Wait()
  38. if failed {
  39. fmt.Println("Test failed")
  40. } else {
  41. fmt.Println("Test passed")
  42. }
  43. }

Playground

英文:

As I understood you are willing to limit the number of routines running simultaneously and verify whether it works properly. I would suggest to write a function which will take a routine as and argument and use mock routine to test it.<br/>
In the following example spawn function runs fn routines count times but no more than limit routines concurrently. I wrapped it into main function to run it at playground but you can use the same approach for your test method.

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;sync&quot;
  5. &quot;time&quot;
  6. )
  7. func spawn(fn func(), count int, limit int) {
  8. limiter := make(chan bool, limit)
  9. spawned := func() {
  10. defer func() { &lt;-limiter }()
  11. fn()
  12. }
  13. for i := 0; i &lt; count; i++ {
  14. limiter &lt;- true
  15. go spawned()
  16. }
  17. }
  18. func main() {
  19. count := 10
  20. limit := 3
  21. var wg sync.WaitGroup
  22. wg.Add(count)
  23. concurrentCount := 0
  24. failed := false
  25. var mock = func() {
  26. defer func() {
  27. wg.Done()
  28. concurrentCount--
  29. }()
  30. concurrentCount++
  31. if concurrentCount &gt; limit {
  32. failed = true // test could be failed here without waiting all routines finish
  33. }
  34. time.Sleep(100)
  35. }
  36. spawn(mock, count, limit)
  37. wg.Wait()
  38. if failed {
  39. fmt.Println(&quot;Test failed&quot;)
  40. } else {
  41. fmt.Println(&quot;Test passed&quot;)
  42. }
  43. }

Playground

答案2

得分: 0

一种可能的方法是使用runtime.Stack()或分析runtime.debug.PrintStack()的输出,以查看给定时间的所有goroutine。

这些选项在“https://stackoverflow.com/q/19094099/6309”中有详细说明。

英文:

One possible approch would be to use runtime.Stack() or analyze the output of runtime.debug.PrintStack() in order to see all goroutines at a given time.

Those options are detailed in "https://stackoverflow.com/q/19094099/6309".

huangapple
  • 本文由 发表于 2015年3月5日 09:47:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/28868596.html
匿名

发表评论

匿名网友

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

确定