Запускаешь горутину, которая пишет результат в канал, и читаешь из него в основном коде:
done := make(chan error, 1)
go func() {
done <- doWork()
}()
err := <-done // блокируемся пока горутина не завершится
Для таймаута — select с time.After. Для множества горутин — sync.WaitGroup или собирай результаты в канал с буфером. В тестах часто используют канал как сигнал завершения: <-done гарантирует, что горутина отработала до проверки результата.