Reputation:
I’ve the following function which prints dots to the terminal while executing Some process, the code is working as expected but now I want to test it. How should I do that
func printdot(finish <-chan struct{}) {
t := time.NewTicker(time.Second)
defer t.Stop()
for {
select {
case <-t.C:
fmt.Print(".")
case <-finish:
return
}
}
}
This is the test
func Test_printdot(t *testing.T) {
finish := make(chan struct{})
start := time.Now()
go printdot(finish)
time.Sleep(1 * time.Second)
sec := time.Since(start).Seconds()
switch int(sec) {
case 0:
// Output:
case 1:
// Output: .
case 2:
// Output: ..
case 3:
// Output: ...
default:
t.Error(“Too much time…”)
}
close(finish)
}
Now the test is continue running without stop even that Im using the finish code , any idea how to improve it ?
Upvotes: 1
Views: 4983
Reputation: 116
Closing a channel doesn't send data, so code will never reach the return
in the goroutine. This trick working with range operator. You can do something like this
package main
import (
"fmt"
"time"
"sync"
)
func printdot(finish <-chan struct{}, wg sync.WaitGroup) {
t := time.NewTicker(time.Second)
defer t.Stop()
defer wg.Done()
for {
select {
case <-t.C:
fmt.Print(".")
case <-finish:
return
}
}
}
Notice that I added sync.WaitGroup for "waiting" while goroutine will end
package main
import (
"fmt"
"time"
"sync"
"testing"
)
func Test_printdot(t *testing.T) {
var wg sync.WaitGroup
wg.Add(1)
finish := make(chan struct{})
start := time.Now()
go printdot(finish, wg)
time.Sleep(3 * time.Second)
sec := time.Since(start).Seconds()
switch int(sec) {
case 0:
// Output:
case 1:
// Output: .
case 2:
// Output: ..
case 3:
// Output: ...
default:
t.Error("Too much time…")
}
finish <- struct{}{}
wg.Wait()
}
Upvotes: 2