【问题标题】:Testing the result of a function running in a background thread测试在后台线程中运行的函数的结果
【发布时间】:2018-02-01 09:18:54
【问题描述】:

我有一个 WebSocket 服务器,我正在尝试正确测试它的一些功能。我有以下情况:

我正在接受 WebSocket 连接并在新连接上调用通道 registerConn <- 以通知 type hub struct。这是枢纽:

type hub struct {
    clients map[client]bool

    registerConn chan client

    // some other fields below...  
}
// This function runs in its own thread forever
func (h *hub) run() {
     for {
           select{
           // A client connects on this channel
           case client := <- h.registerConn:
                  h.clients[client] = true
           }
     }
}

现在,我想在hub_test.go中测试这个功能:

func TestRegisterClientWSConnections(t *testing.T){
    for _, cl := range testClients {
        thub.registerConn <- cl
    }

    // TODO: Is this a good way to test?
    time.Sleep(1 * time.Second)

    // I want to know if the testClients have been added to my clients map
    for _, cl := range testClients {
        if thub.clients[cl] == false {
            t.Error("Client ", cl, " not found in the registered clients")
        }
    }
}

由于集线器上的 run() 函数在后台线程中运行,因此在主线程中进行检查(第二个 for 循环)之前,后台线程中的客户端注册(第一个 for 循环)尚未完成,并且由于这个原因它失败了。

解决方法是添加time.Sleep() 等待注册完成。其他解决方法是添加一个通道来通知测试添加完成。

我不想只为测试添加新频道,因为这会导致不必要的代码。另一方面,在测试中使用time.Sleep() 似乎不是一个好习惯。 (或者是吗?)

我可以通过什么方式测试这个案例?

【问题讨论】:

标签: go


【解决方案1】:

正如建议的答案,Gomega 有一个非常优雅的解决方案

测试现在看起来像这样:

编辑:

func TestRegisterClientsFromWSConnection(t *testing.T){
    g := NewGomegaWithT(t)

    for _, cl := range testClients {
        thub.registerConn <- cl
    }

    g.Eventually(thub.clients).Should(HaveLen(len(thub.clients)), fmt.Sprintf("client map must have len %d", len(testClients)))
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-26
    • 2023-03-14
    • 2019-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多