7

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 (
    "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
}
3
  • 1
    What exactly are you trying to verify? That you are starting 16 goroutines? I am not quite following the problem you are trying to solve. Commented Mar 5, 2015 at 5:21
  • Why do you send the int to the jobs channel ? It seems like you have 2 designs there. Commented Mar 5, 2015 at 15:55
  • the link is broken Commented Jan 27, 2022 at 19:25

2 Answers 2

1

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

Sign up to request clarification or add additional context in comments.

Comments

0

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 "How to dump goroutine stacktraces?".

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.