SoFunction
Updated on 2025-03-03

Go language context test source code analysis details

1. Test example analysis

example_test.go, shows 4 examples of the With-series

func ExampleWithCancel() {
  gen := func(ctx ) <-chan int {
    dst := make(chan int)
    n := 1
    go func() {
      for {
        select {
        case <-():
          return // returning not to leak the goroutine
        case dst <- n:
          n++
        }
      }
    }()
    return dst
  }

  ctx, cancel := (())
  defer cancel() // cancel when we are finished consuming integers

  for n := range gen(ctx) {
    (n)
    if n == 5 {
      break
    }
  }
  // Output:
  // 1
  // 2
  // 3
  // 4
  // 5
}

Structural analysis,genis a function, the return value is a channel,for range channelIt has special significance. For will loop to read data from the channel until the channel is closed(), otherwise it will be an infinite loop.

Coroutines inside gen are typical closures. For range will constantly trigger reading, and for select will continuously trigger writing. After the main coroutine is read 5 times, the main function will be terminated and the defer function will be triggered, that is, cancel the corresponding callback of the operation. At this time, the done channel will be closed, and the coroutines inside gen will exit normally.

This example is to test the context of the cancel signal, and the cancel function call is placedmainofdeferin the function.

const shortDuration = 1 * 
func ExampleWithDeadline() {
  d := ().Add(shortDuration)
  ctx, cancel := ((), d)

  // Even though ctx will be expired, it is good practice to call its
  // cancellation function in any case. Failure to do so may keep the
  // context and its parent alive longer than necessary.
  defer cancel()

  select {
  case <-(1 * ):
    ("overslept")
  case <-():
    (())
  }

  // Output:
  // context deadline exceeded
}

deadlineThis example ofmainofdeferThere are also active calls to cancel functions in it. In fact, printing can show whether deadline works as expected.

func ExampleWithTimeout() {
  ctx, cancel := ((), shortDuration)
  defer cancel()

  select {
  case <-(1 * ):
    ("overslept")
  case <-():
    (()) // prints "context deadline exceeded"
  }

  // Output:
  // context deadline exceeded
}

timeoutonlydeadlineA abbreviation of .

func ExampleWithValue() {
  type favContextKey string

  f := func(ctx , k favContextKey) {
    if v := (k); v != nil {
      ("found value:", v)
      return
    }
    ("key not found:", k)
  }

  k := favContextKey("language")
  ctx := ((), k, "Go")

  f(ctx, k)
  f(ctx, favContextKey("color"))

  // Output:
  // found value: Go
  // key not found: color
}

and()It is an access operation. When fetching, if the key is not found, nil will be returned.

2. Unit Testing

context_text.go,x_test.goIt's unit test, example_test.goIt is an example, benchmark_test.go is a benchmark, and net_test.go shows deadline support for net packages.

Let’s first look at the context_text.go of the unit test.

type testingT interface {}

type otherContext struct {}
func quiescent(t testingT)  {}
func XTestBackground(t testingT) {}
func XTestTODO(t testingT) {}
func XTestWithCancel(t testingT) {}
func contains(m map[canceler]struct{}, key canceler) bool {}
func XTestParentFinishesChild(t testingT) {}
func XTestChildFinishesFirst(t testingT) {}
func testDeadline(c Context, name string, t testingT) {}
func XTestDeadline(t testingT) {}
func XTestTimeout(t testingT) {}
func XTestCanceledTimeout(t testingT) {}
func XTestValues(t testingT) {}
func XTestAllocs(t testingT, testingShort func() bool, testingAllocsPerRun func(int, func()) float64) {}
func XTestSimultaneousCancels(t testingT) {}
func XTestInterlockedCancels(t testingT) {}
func XTestLayersCancel(t testingT) {}
func XTestLayersTimeout(t testingT) {}
func XTestCancelRemoves(t testingT) {}
func XTestWithCancelCanceledParent(t testingT) {}
func XTestWithValueChecksKey(t testingT) {}
func XTestInvalidDerivedFail(t testingT) {}
func recoveredValue(fn func()) (v interface{}) {}
func XTestDeadlineExceededSupportsTimeout(t testingT) {}
type myCtx struct {}
type myDoneCtx struct {}
func (d *myDoneCtx) Done() <-chan struct{} {}
func XTestCustomContextGoroutines(t testingT) {}

Most of the parameter types of test functions exposed are testT interface types, but this source file is not implementedtestingTInterface,

func TestBackground(t *)                      { XTestBackground(t) }
func TestTODO(t *)                            { XTestTODO(t) }
func TestWithCancel(t *)                      { XTestWithCancel(t) }
func TestParentFinishesChild(t *)             { XTestParentFinishesChild(t) }
func TestChildFinishesFirst(t *)              { XTestChildFinishesFirst(t) }
func TestDeadline(t *)                        { XTestDeadline(t) }
func TestTimeout(t *)                         { XTestTimeout(t) }
func TestCanceledTimeout(t *)                 { XTestCanceledTimeout(t) }
func TestValues(t *)                          { XTestValues(t) }
func TestAllocs(t *)                          { XTestAllocs(t, , ) }
func TestSimultaneousCancels(t *)             { XTestSimultaneousCancels(t) }
func TestInterlockedCancels(t *)              { XTestInterlockedCancels(t) }
func TestLayersCancel(t *)                    { XTestLayersCancel(t) }
func TestLayersTimeout(t *)                   { XTestLayersTimeout(t) }
func TestCancelRemoves(t *)                   { XTestCancelRemoves(t) }
func TestWithCancelCanceledParent(t *)        { XTestWithCancelCanceledParent(t) }
func TestWithValueChecksKey(t *)              { XTestWithValueChecksKey(t) }
func TestInvalidDerivedFail(t *)              { XTestInvalidDerivedFail(t) }
func TestDeadlineExceededSupportsTimeout(t *) { XTestDeadlineExceededSupportsTimeout(t) }
func TestCustomContextGoroutines(t *)         { XTestCustomContextGoroutines(t) }

This isx_test.goThe content is directly usedType to implement the testingT interface.

Let’s first analyze the implementation of the testingT interface.

type T struct {
  common
  isParallel bool
  context    *testContext
}
func (t *T) Deadline() (deadline , ok bool) {
  deadline = 
  return deadline, !()
}

Notice:No implementation type, Deadline() returns the deadline information stored in it.

Embedded, most of the method sets come to common:

Error(args ...interface{})
Errorf(format string, args ...interface{})
Fail()
FailNow()
Failed() bool
Fatal(args ...interface{})
Fatalf(format string, args ...interface{})
Helper()
Log(args ...interface{})
Logf(format string, args ...interface{})
Name() string
Skip(args ...interface{})
SkipNow()
Skipf(format string, args ...interface{})
Skipped() bool

Parallel()Is it fromImplementation: When a test case is repeatedly executed multiple times, concurrent parameters can be enabled.

This is the end of this article about the detailed analysis of Go context test source code. For more relevant Go context test source code analysis content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!