12

When I do ut of golang, I sometimes need to test the result in goroutine, I was using time.Sleep to test, I am wondering is there any better way to test.

let's say I have an example code like this

func Hello() {
    go func() {
        // do something and store the result for example in db
    }()
    // do something
}

Then when I test the func, I want to test both result in goroutine, I am doing this:

 func TestHello(t *testing.T) {
        Hello()
        time.Sleep(time.Second) // sleep for a while so that goroutine can finish
        // test the result of goroutine
 }

is there any better way to test this?

Basically, in real logic, I don't care the result in goroutine, I don't need to wait for it finished. but in test, I want to check after it finished.

harrycmfan
  • 1,055
  • 3
  • 9
  • 12
  • I have heard about using context, but not able to find an exact example similar to my use case – harrycmfan Sep 12 '17 at 02:57
  • I don't quite understand what you are trying to do. Why are you setting `b` in a goroutine? If you don't want to use sleep, use a waitgroup. https://stackoverflow.com/questions/19208725/example-for-sync-waitgroup-correct – reticentroot Sep 12 '17 at 03:27
  • sorry, I think my example is confusing, I changed my example – harrycmfan Sep 12 '17 at 04:24

2 Answers2

7

Most questions of "How do I test X?" tend to boil down to X being too big.

In your case, the simplest solution is not to use goroutines in tests. Test each function in isolation. Change your code to:

func Hello() {
    go updateDatabase()
    doSomething()
}

func updateDatabase() {
    // do something and store the result for example in db
}

func doSomething() {
    // do something
}

Then write separate tests for updateDatabase and doSomething.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
  • 10
    Sometimes you need to test that the goroutine with the func has been actually called with an expected set of arguments. How should such cases be tested then? – Oleh Holovko Jun 19 '19 at 12:55
  • @OlehHolovko: Pretty much the same way you check whether any func, in a goroutine or not, is called properly. Probably with some dependency injection. Similar questions have been asked many times here. I suggest a search, and if you can't find an answer, a separate question is probably warranted. – Jonathan Hall Jun 19 '19 at 12:57
6

If you really want to check the result of a goroutine, you should use a channel like so:

package main

import (
    "fmt"
)

func main() {
    // in test
    c := Hello()
    if <-c != "done" {
        fmt.Println("assert error")
    }

    // not want to check result
    Hello()
}

func Hello() <-chan string {
    c := make(chan string)
    go func() {
        fmt.Println("do something")
        c <- "done"
    }()
    return c
}

https://play.golang.org/p/zUpNXg61Wn

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
faisal burhanudin
  • 1,101
  • 12
  • 16