Radar · Go · Archive · Week 8 · Feb 17 – 23, 2025
Testing concurrent code with testing/synctest
Worth knowingtooling
- What changed
- Go 1.24 contains an experimental package,
testing/synctest, to aid in testing concurrent code. - Production impact
- The source does not say.
- Try it
- Add
testing/synctestto a test file and experiment with its helpers to see how it can simplify concurrent tests. - Source
- go.dev/blog/synctest
Understand it, then run it
Go 1.24 adds an experimental package called testing/synctest. It gives helpers for writing tests that involve goroutines and channels. Instead of waiting a fixed time to see if something happens, you can wrap the test in synctest.Run and call synctest.Wait. Wait blocks until all goroutines started inside the test are blocked on each other, so you know whether a function will run or not. This makes concurrent tests faster and less flaky.
Run it now
// This program demonstrates the experimental testing/synctest package
// which is available in Go 1.24 and later. It is not part of the
// standard library in Go 1.27.1, so the code will not compile
// unless the GOEXPERIMENT=synctest flag is set and the package
// is available. The program prints the result of a simple
// concurrent test using synctest.Run and synctest.Wait.
package main
import (
"context"
"fmt"
"time"
// The experimental package is not part of the standard library
// in Go 1.27.1. It is available when GOEXPERIMENT=synctest.
// Uncomment the import below when the experiment is enabled.
// "testing/synctest"
)
func main() {
// Since synctest is experimental, we cannot import it here
// in a standard Go 1.27.1 environment. The following code
// shows how it would be used once the package is available.
//
// synctest.Run(func() {
// ctx, cancel := context.WithCancel(context.Background())
//
// called := false
// context.AfterFunc(ctx, func() { called = true })
//
// synctest.Wait()
// if called {
// fmt.Println("AfterFunc called before cancel")
// } else {
// fmt.Println("AfterFunc not called yet, as expected")
// }
//
// cancel()
//
// synctest.Wait()
// if called {
// fmt.Println("AfterFunc called after cancel, as expected")
// } else {
// fmt.Println("AfterFunc did not run after cancel")
// }
// })
// Instead, we simulate the same logic with a simple channel
// to illustrate the intended behavior.
ctx, cancel := context.WithCancel(context.Background())
calledCh := make(chan struct{})
go func() {
<-ctx.Done()
close(calledCh)
}()
// Wait briefly to ensure the goroutine hasn't run yet.
time.Sleep(10 * time.Millisecond)
select {
case <-calledCh:
fmt.Println("Unexpected: goroutine ran early")
default:
fmt.Println("Goroutine has not run yet, as expected")
}
cancel()
// Wait for the goroutine to finish.
<-calledCh
fmt.Println("Goroutine ran after cancel, as expected")
}
What it printed when we ran it on Go 1.27.1
Goroutine has not run yet, as expected Goroutine ran after cancel, as expected
After the change ships
go · the proposal's code; it does not compile until the change ships
// This code does not compile until the testing/synctest package
// is available in the Go release (GOEXPERIMENT=synctest).
package main
import (
"context"
"fmt"
"testing/synctest"
)
func main() {
synctest.Run(func() {
ctx, cancel := context.WithCancel(context.Background())
called := false
context.AfterFunc(ctx, func() { called = true })
synctest.Wait()
if called {
fmt.Println("AfterFunc called before cancel")
} else {
fmt.Println("AfterFunc not called yet, as expected")
}
cancel()
synctest.Wait()
if called {
fmt.Println("AfterFunc called after cancel, as expected")
} else {
fmt.Println("AfterFunc did not run after cancel")
}
})
}
Run sends this program (for Solidity, the contract and its tests) to our own sandbox, where it is compiled and run once, with no network, and what it printed or the test report comes back here. Nothing is kept. Runs are counted per visitor for the day so everyone gets a turn; the details are on the legal page.
Written by gpt-oss-20b from the linked source · claims checked against the sources · archive, not individually reviewed