user6171746
user6171746

Reputation:

Golang test for go-routine with channel

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

Answers (1)

Magiq
Magiq

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

Related Questions