Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test Golang Goroutine

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
}
like image 920
xbeta Avatar asked Mar 05 '15 01:03

xbeta


People also ask

How do you unit test go channels?

create channels of the appropriate type for my function under test. pass those channels into o. sum() and run the function on a separate go routine. create a loop that will send data to the values channel.

What is Goroutine Golang?

Golang provides goroutines to support concurrency in Go. A goroutine is a function that executes simultaneously with other goroutines in a program and are lightweight threads managed by Go. A goroutine takes about 2kB of stack space to initialize.

Does go test run tests in parallel?

The 'go test' command may run tests for different packages in parallel as well, according to the setting of the -p flag (see 'go help build').

How do you wait for a Goroutine to finish?

The WaitGroup type of sync package, is used to wait for the program to finish all goroutines launched from the main function. It uses a counter that specifies the number of goroutines, and Wait blocks the execution of the program until the WaitGroup counter is zero.


1 Answers

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

like image 142
Sundrique Avatar answered Oct 03 '22 06:10

Sundrique