如何告诉我的测试等待goroutine中的回调?

时间:2015-07-31 15:39:32

标签: go goroutine

我正在使用dockerclient https://github.com/samalba/dockerclient,它有一个基于频道的API来监听事件client.MonitorEvents()和一个方便的回调方法client.StartMonitorEvents(callbackHandler)

我想测试处理程序是否被调用。当然,dockerclient处理goroutine中的事件。

现在,我的处理程序只是吐出一个日志。如果我在测试中等待,一切都会得到处理。如果我不这样做,它会在它处理任何事情之前退出:

func eventCallback(event *dockerclient.Event, ec chan error, args ...interface{}) {
  log.Printf("Received event: %#v\n", *event)
}

我的测试似乎很简单:

func TestReceiveEvent(t *testing.T) {
   createAndMonitorEvents(server.URL)
   <- eventReady
   eventWriter.Write([]byte(someEvent))
   // test for something here
}

当然,除非因为goroutine而放入time.Sleep(),否则它不起作用。

我如何告诉我的测试,“等待其他例程在运行测试之前完成其工作”,而不是进行一些任意的睡眠?我希望测试我的处理程序正确处理事件。

备用界面client.MonitorEvents()会返回一个频道,这会让我获得更大的控制权,但是频道上的接收会发出无限nil个事件。

更新:

根据要求,createAndMonitorEvents是:

func createAndMonitorEvents(url string) {
  // Init the client
  docker, _ := dockerclient.NewDockerClient(url, nil)

  // Listen to events
  stopchan := make(chan struct{})

  go func() {
    eventErrChan, err := docker.MonitorEvents(nil, stopchan)
    if err != nil {
        return
    }

    for e := range eventErrChan {
        if e.Error != nil {
            return
        }
        eventCallback(&e.Event, nil)
    }
    fmt.Println("monitor in place")
  }()
}

3 个答案:

答案 0 :(得分:1)

我认为当您nil获得MonitorEvents时,您只是看到事件频道已关闭(source of MonitorEvents包含close(eventOrErrorChan),支持此功能) 。 evt, ok := <-c可让您直接检查(ok在关闭时是否为假),for evt := range c将在关闭后停止。通常,在收到任何先前发送的值之后,从封闭信道接收specified到“[yield]元素类型的零值”

关于等待回调的问题:回调可以关闭一个频道。 (或发送给它。)然后您的测试可以使用select等待指定的时间长度:

select {
case <-c:
        /* ...success... */
case <-time.After(5 * time.Second):
        /* timed out */
}

如果您知道某些错误情况导致处理程序无法完成或未运行,则可能会在不同的通道上发出这些情况,或者向c发送不同的值。

答案 1 :(得分:1)

我认为这可以提供帮助

  

WaitGroup等待完成goroutine的集合。主goroutine调用Add来设置要等待的goroutines的数量。然后每个goroutine运行并在完成后调用Done。同时,Wait可以用来阻止所有goroutine完成。

http://golang.org/pkg/sync/#example_WaitGroup

答案 2 :(得分:0)

“我如何告诉我的测试,”等待其他例程在运行测试之前完成其工作“,而不是进行任意的睡眠?”

您要么发送频道要么关闭频道。调用者正在接收执行块直到发生信号。我真的没有看到如何将你的代码工作成有意义的东西......你不能在函数中分配停止通道,你必须将它传递给函数,以便调用者可以监听它。比如这甚至可以编译?

func TestReceiveEvent(t *testing.T) {
   createAndMonitorEvents(server.URL)
   <- eventReady // undeclared variable, and discarding the event you recieved?
   eventWriter.Write([]byte(someEvent)) //and another variable that is not declared
   // test for something here
}

也许和想法会帮助你开始......

func createAndMonitorEvents(url string, done chan bool) {
      //the codes
      close(done)
}


func TestReceiveEvent(t *testing.T) {
  eventReady := make(chan bool)
    createAndMonitorEvents(server.URL, eventReady)
    <- eventReady
    eventWriter.Write([]byte(someEvent)) // dis still don't exist though
    // test for something here

}