> ## Content Index
> Fetch the complete content index at: https://huizhou92.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Go 1.24: synctest
- URL: https://huizhou92.com/go-1-24-synctest/
- Published: 2024-12-23T10:19:45.000Z
- Updated: 2026-09-08T02:29:37.000Z
- Description: Go 1.24: synctest. Introduction Testing concurrent code in Go has always been challenging. This is especially true for test cases involving time-dependent。
- Author: huizhou92
- Tags: #Migrated-1788833207488, #Import 2026-09-08 02:07

### Introduction

Testing concurrent code in Go has always been challenging. This is especially true for test cases involving time-dependent behavior. Traditional testing methods often rely on the actual system clock and synchronization mechanisms, leading to slow and unreliable tests.

For instance, when testing the expiration feature of the `go-cache` library, a common approach would look like this:

> [*go-cache*](https://github.com/patrickmn/go-cache?ref=huizhou92.com) *is a popular Go caching library that supports time-to-live (TTL) and periodic cleanup of expired cache items. It is well-suited for caching data and automatically deletes expired entries.*

List 1: `TestGoCacheEntryExpires` testing cache in the usual way

```go
func TestGoCacheEntryExpires(t *testing.T) {   
    c := cache.New(5*time.Second, 10*time.Second)   
    c.Set("foo", "bar", cache.DefaultExpiration)   
    v, found := c.Get("foo")   
    assert.True(t, found)   
    assert.Equal(t, "bar", v)   
    time.Sleep(5 * time.Second)   
    v, found = c.Get("foo")   
    assert.False(t, found)   
    assert.Nil(t, v)   
}
```

Running this test requires waiting for 5 seconds for the cache entry to expire:

```shell
➜  synctest git:(main) ✗ time go test go-cache_test.go   
ok      command-line-arguments  5.012s   
go test go-cache_test.go  0.38s user 1.27s system 27% cpu 6.049 total
```

#### The `testing/synctest` Approach

Starting with Go 1.24, the `testing/synctest` package significantly improves this process. Here's how the same test case can be rewritten using `testing/synctest`  
  
List 2: `TestGoCacheEntryExpiresWithSynctest` testing cache in the synctest

```go
func TestGoCacheEntryExpiresWithSynctest(t *testing.T) {   
    c := cache.New(2*time.Second, 5*time.Second)   
    synctest.Run(func() {   
        c.Set("foo", "bar", cache.DefaultExpiration)   
        if got, exist := c.Get("foo"); !exist && got != "bar" {   
            t.Errorf("c.Get(k) = %v, want %v", got, "bar")   
        }   
        time.Sleep(1 * time.Second)   
        if got, exist := c.Get("foo"); !exist && got != "bar" {   
            t.Errorf("c.Get(k) = %v, want %v", got, "bar")   
        }   
        time.Sleep(3 * time.Second)   
        if got, exist := c.Get("foo"); exist {   
            t.Errorf("c.Get(k) = %v, want %v", got, nil)   
        }   
    })   
}
```

Running this test

```shell
➜  synctest git:(main) ✗ time GOEXPERIMENT=synctest gotip test -run TestGoCacheEntryExpiresWithSynctest   
PASS   
ok      blog-example/go/go1.24/synctest 0.009s   
GOEXPERIMENT=synctest gotip test -run TestGoCacheEntryExpiresWithSynctest  0.36s user 1.23s system 171% cpu 0.933 total
```

The test now completes in just `0.009s`.

> **Why is it so fast?**  
>  
> Unveiling `testing/synctest`

[testing/synctest](https://github.com/golang/go/issues/67434?ref=huizhou92.com) simplifies testing concurrent code by using virtual clocks and `goroutine` groups (also known as "bubbles"). This makes tests both fast and reliable. The package offers two core functions:

```go
func Run(f func()) { synctest.Run(f) }   
func Wait() { synctest.Wait() }
```

#### Key Features

1. **Run**: Executes the provided function `f` in a new `goroutine` under its bubble, ensuring that the virtual clock controls all related `goroutines`.
2. **Wait**: Synchronizes the bubble’s `goroutines` and blocks the main `goroutine` until all others are in a `durably blocked` state.

A `durably blocked` state occurs when `goroutines` are waiting on:

- Channel send/receive within the bubble.
- `select` statements involving bubble channels
- `sync.Cond.Wait`
- `time.Sleep`  
However, `goroutines` blocked by system calls or external events are not considered `durably blocked`.

#### Virtual Clocks

Each bubble has a virtual clock starting from `2000-01-01 00:00:00 UTC`. The clock advances only when all `goroutines` are idle. This allows `time.Sleep` calls to be completed instantly if all `goroutines` are idle, significantly speeding up tests.

List 3: `TestSynctest` Virtual Clocks are not affected by program run time

```go
func TestSynctest(t *testing.T) {   
    synctest.Run(func() {   
       before := time.Now()   
       fmt.Println("before", before)   
       f1 := func() {   
          for i := 0; i < 10e9; i++ { // time consuming, It's about 3s in my machine   
          }   
       }   
       go f1()   
       synctest.Wait()     //wait f1   
       after := time.Now() // time is not affected by the running time of f1   
       fmt.Println("after", after)   
    })   
}
```

Output:

```shell
➜  synctest git:(main) ✗ time GOEXPERIMENT=synctest gotip test -run TestSynctest   
before 2000-01-01 08:00:00 +0800 CST m=+946164282.733407335   
after 2000-01-01 08:00:00 +0800 CST m=+946164282.733407335   
PASS   
ok      blog-example/go/go1.24/synctest 3.131s   
GOEXPERIMENT=synctest gotip test -run TestSynctest  3.45s user 1.25s system 133% cpu 3.533 total
```

**Even computationally intensive functions do not affect the virtual clock’s time.**

### Conclusion

The `testing/synctest` package introduces a powerful way to test concurrent Go code efficiently and reliably by leveraging virtual clocks and `goroutine` control. It eliminates the need for real-time waiting and makes time-dependent tests faster and more predictable.

### Reference

1. [synctest.go](https://github.com/golang/go/blob/05d8984781f7cf2f0f39b53699a558b6a1965c6c/src/testing/synctest/synctest.go?ref=huizhou92.com)

---

more read about go 1.24

[Go1.24Edit description![](https://huizhou92.com/content/images/2026/09/0-72d6045056596b01909af91f4486650c3136a20e-jpeg.jpg)](https://medium.huizhou92.com/list/96f77bdb6fb5?ref=huizhou92.com)