测试 Golang 的 Goroutine

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

Test Golang Goroutine

问题

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

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

我有以下示例代码:

import (
	"testing"
	"github.com/stretchr/testify/assert"
)

func createList(job int, done chan bool) {
	time.Sleep(500)
	// do something
	time.Sleep(500)
	done <- true
	return
}

func TestNewList(t *testing.T) {
	list := NewList()
	if assert.NotNil(t, list) {
		const numGoRoutines = 16
		jobs := make(chan int, numGoRoutines)
		done := make(chan bool, 1)

		for j := 1; j <= numGoRoutines; j++ {
			jobs <- j
			go createList(j, done)
			fmt.Println("sent job", j)
		}
		close(jobs)
		fmt.Println("sent all jobs")
		<-done
	}
}
英文:

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..

import (
	&quot;testing&quot;
	&quot;github.com/stretchr/testify/assert&quot;
)

func createList(job int, done chan bool) {
	time.Sleep(500)
	// do something
	time.Sleep(500)
	done &lt;- true
	return
}

func TestNewList(t *testing.T) {
  list := NewList()
  if assert.NotNil(t, list) {
    const numGoRoutines = 16
	jobs := make(chan int, numGoRoutines)
	done := make(chan bool, 1)

	for j := 1; j &lt;= numGoRoutines; j++ {
		jobs &lt;- j
		go createList(j, done)
	    fmt.Println(&quot;sent job&quot;, j)
	}
	close(jobs)
	fmt.Println(&quot;sent all jobs&quot;)
	&lt;-done
}

答案1

得分: 1

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

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

package main

import (
    "fmt"
    "sync"
    "time"
)

func spawn(fn func(), count int, limit int) {
    limiter := make(chan bool, limit)

    spawned := func() {
        defer func() { <-limiter }()
        fn()
    }

    for i := 0; i < count; i++ {
        limiter <- true
        go spawned()
    }
}

func main() {

    count := 10
    limit := 3

    var wg sync.WaitGroup
    wg.Add(count)

    concurrentCount := 0
    failed := false

    var mock = func() {
        defer func() {
            wg.Done()
            concurrentCount--
        }()

        concurrentCount++
        if concurrentCount > limit {
            failed = true // test could be failed here without waiting all routines finish
        }

        time.Sleep(100)
    }

    spawn(mock, count, limit)

    wg.Wait()

    if failed {
        fmt.Println("Test failed")
    } else {
        fmt.Println("Test passed")
    }
}

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.

package main

import (
    &quot;fmt&quot;
    &quot;sync&quot;
    &quot;time&quot;
)

func spawn(fn func(), count int, limit int) {
    limiter := make(chan bool, limit)

    spawned := func() {
        defer func() { &lt;-limiter }()
        fn()
    }

    for i := 0; i &lt; count; i++ {
        limiter &lt;- true
        go spawned()
    }
}

func main() {

    count := 10
    limit := 3

    var wg sync.WaitGroup
    wg.Add(count)

    concurrentCount := 0
    failed := false

    var mock = func() {
        defer func() {
            wg.Done()
            concurrentCount--
        }()

        concurrentCount++
        if concurrentCount &gt; limit {
            failed = true // test could be failed here without waiting all routines finish
        }

        time.Sleep(100)
    }

    spawn(mock, count, limit)

    wg.Wait()

    if failed {
        fmt.Println(&quot;Test failed&quot;)
    } else {
        fmt.Println(&quot;Test passed&quot;)
    }
}

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:

确定