测试在后台线程中运行的函数的结果



我有一个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()似乎不是一个好的做法。(还是吗?

我可以通过哪些方式测试这种情况?

与建议的答案一样,有一个非常优雅的解决方案,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)))
}

最新更新