I have a WebSocket server and I am trying to properly test some of its functionality. I have the following scenario:
I am accepting WebSocket connections and calling a channel registerConn <-
on a new connection to inform a type hub struct
. This is the hub:
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
}
}
}
Now, I want to test this function in 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")
}
}
}
Since the run()
function on the hub is running in a backround thread the registration of the clients (first for loop) in the background thread is not finished before the check is made (second for loop) in the main thread and it fails for that reason.
The workaround is to add time.Sleep()
to wait for the registration to finish. Other workaround is to add a channel to inform the test for the completion of the addition.
I don't want to add new channels for the test only, as it would result in unnecessary code. On the other hand, using time.Sleep()
in a test doesn't seem to be a good practice. (Or is it?)
In what ways can I test this case?
As in the suggested answer, there is a very elegant solution with Gomega
The test now looks like this:
EDIT:
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)))
}