Go语言context test源码分析详情

目录
  • 1.测试例子分析
  • 2.单元测试

1.测试例子分析

example_test.go,展示了With-系列的4个例子

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

  ctx, cancel := context.WithCancel(context.Background())
  defer cancel() // cancel when we are finished consuming integers

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

结构分析,gen是一个函数,返回值是一个信道, for range channel是有特殊意义的, for会循环从channel读数据,直到channel被close(),不然就是无限循环.

gen内部的协程就是典型的闭包,for range会不断触发读,gen内部的for select 会不断触发写,主协程读5次之后,会结束main函数,会触发defer函数, 也就是取消操作对应的回调,此时done信道会被close,gen内部的协程会正常退出.

这个例子是测试支持取消信号的上下文,取消函数的调用放在了maindefer函数中.

const shortDuration = 1 * time.Millisecond
func ExampleWithDeadline() {
  d := time.Now().Add(shortDuration)
  ctx, cancel := context.WithDeadline(context.Background(), 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 <-time.After(1 * time.Second):
    fmt.Println("overslept")
  case <-ctx.Done():
    fmt.Println(ctx.Err())
  }

  // Output:
  // context deadline exceeded
}

deadline的这个例子,在maindefer中也有主动调用取消函数的. 实际上通过打印可以显示deadline是否按预期工作.

func ExampleWithTimeout() {
  ctx, cancel := context.WithTimeout(context.Background(), shortDuration)
  defer cancel()

  select {
  case <-time.After(1 * time.Second):
    fmt.Println("overslept")
  case <-ctx.Done():
    fmt.Println(ctx.Err()) // prints "context deadline exceeded"
  }

  // Output:
  // context deadline exceeded
}

timeout只是deadline的一种简写.

func ExampleWithValue() {
  type favContextKey string

  f := func(ctx context.Context, k favContextKey) {
    if v := ctx.Value(k); v != nil {
      fmt.Println("found value:", v)
      return
    }
    fmt.Println("key not found:", k)
  }

  k := favContextKey("language")
  ctx := context.WithValue(context.Background(), k, "Go")

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

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

context.WithValueContext.Value()是存取操作, 取的时候,如果key没找到,会返回nil.

2.单元测试

context_text.go,x_test.go是单元测试, example_test.go是示例,benchmark_test.go是基准测试, net_test.go展示了deadline对net包的支持.

先看单元测试的context_text.go.

type testingT interface {}

type otherContext struct {}
func quiescent(t testingT) time.Duration {}
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) {}

这暴露的大多测试函数的参数类型是testingT接口类型,但这个源文件中没有实现testingT接口的,

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

这是x_test.go的内容,直接是用testing.T类型来实现testingT接口.

那先分析一下testing.T对testingT接口的实现.

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

注意:testing.T.context不是context.Context的实现类型, Deadline()返回了t.context中存储的deadline信息.

testing.T内嵌了testing.common,大部分方法集都来至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()是由testing.T实现,某个测试用例多次重复执行时, 可启用并发参数.

到此这篇关于Go语言context test源码分析详情的文章就介绍到这了,更多相关Go语言context test源码分析内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 深入理解 Go 语言中的 Context

    Hi,大家好,我是明哥. 在自己学习 Golang 的这段时间里,我写了详细的学习笔记放在我的个人微信公众号 <Go编程时光>,对于 Go 语言,我也算是个初学者,因此写的东西应该会比较适合刚接触的同学,如果你也是刚学习 Go 语言,不防关注一下,一起学习,一起成长. 我的在线博客:http://golang.iswbm.com 我的 Github:github.com/iswbm/GolangCodingTime 1. 什么是 Context? 在 Go 1.7 版本之前,context 还

  • 对Go语言中的context包源码分析

    目录 一.包说明分析 二.包结构分析 三.Context接口类型分析 四.后续分析规划 五.基于实现类型到常用函数 六.With-系列函数 七.扩展功能以及如何扩展 八.补充 一.包说明分析 context包:这个包分析的是1.15 context包定义了一个Context类型(接口类型),通过这个Context接口类型, 就可以跨api边界/跨进程传递一些deadline/cancel信号/request-scoped值. 发给server的请求中需要包含Context,server需要接收C

  • 详解Go语言的context包从放弃到入门

    一.Context包到底是干嘛用的 我们会在用到很多东西的时候都看到context的影子,比如gin框架,比如grpc,这东西到底是做啥的? 大家都在用,没几个知道这是干嘛的,知其然而不知其所以然, 谁都在CRUD,谁都觉得if else就完了,有代码能copy我也行,原理啥啥不懂不重要,反正就是一把梭 原理说白了就是: 当前协程取消了,可以通知所有由它创建的子协程退出 当前协程取消了,不会影响到创建它的父级协程的状态 扩展了额外的功能:超时取消.定时取消.可以给子协程共享数据 二.主协程退出通

  • golang中context的作用详解

    当一个goroutine可以启动其他goroutine,而这些goroutine可以启动其他goroutine,依此类推,则第一个goroutine应该能够向所有其它goroutine发送取消信号. 上下文包的唯一目的是在goroutine之间执行取消信号,而不管它们如何生成.上下文的接口定义为: type Context interface { Deadline() (deadline time.Time, ok bool) Done() <- chan struct{} Err() erro

  • Go语言context test源码分析详情

    目录 1.测试例子分析 2.单元测试 1.测试例子分析 example_test.go,展示了With-系列的4个例子 func ExampleWithCancel() {   gen := func(ctx context.Context) <-chan int {     dst := make(chan int)     n := 1     go func() {       for {         select {         case <-ctx.Done():      

  • Go语言io pipe源码分析详情

    目录 1.结构分析 2.pipe sruct分析 3.PipeReader对外暴露的是读/关闭 4.写法 5.总结 pipe.go分析: 这个文件使用到了errors包,也是用到了sync库. 文件说明:pipe是一个适配器,用于连接Reader和Writer. 1.结构分析 对外暴露的是一个构造函数和构造的两个对象. 两个对象分别暴露了方法,同时这两个对象还有一个共同的底层对象. 实际上,这两个对象暴露的方法是直接调用底层对象的, 那么核心还是在底层对象上,只是通过两个对象和一个构造方法将底层

  • Go语言读写锁RWMutex的源码分析

    目录 前言 RWMutex 总览 深入源码 数据结构 RLock() RUnlock() Lock() Unlock() 常见问题 实战一下 前言 在前面两篇文章中 初见 Go Mutex .Go Mutex 源码详解,我们学习了 Go语言 中的 Mutex,它是一把互斥锁,每次只允许一个 goroutine 进入临界区,可以保证临界区资源的状态正确性.但是有的情况下,并不是所有 goroutine 都会修改临界区状态,可能只是读取临界区的数据,如果此时还是需要每个 goroutine 拿到锁依

  • 解析Mybatis判断表达式源码分析

    在我们开发过程中用 Mybatis 经常会用到下面的例子 Mapper如下 Map<String ,String > testArray(@Param("array") String [] array); XMl中的sql如下 <select id="testArray" resultType="map"> select * from t_ams_ac_pmt_dtl where cpt_pro=#{cptProp} &l

  • Spring源码分析容器启动流程

    目录 前言 源码解析 1.初始化流程 流程分析 核心代码剖析 2.刷新流程 流程分析 核心代码剖析 前言 本文基于 Spring 的 5.1.6.RELEASE 版本 Spring的启动流程可以归纳为三个步骤: 1.初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中 2.将配置类的BeanDefinition注册到容器中 3.调用refresh()方法刷新容器 Spring Framework 是 Java 语言中影响最为深远的框架之一,其

  • 由浅入深讲解Javascript继承机制与simple-inheritance源码分析

    老生常谈的问题,大部分人也不一定可以系统的理解.Javascript语言对继承实现的并不好,需要工程师自己去实现一套完整的继承机制.下面我们由浅入深的系统掌握使用javascript继承的技巧. 1. 直接使用原型链 这是最简粗暴的一种方式,基本没法用于具体的项目中.一个简单的demo如下: function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return th

  • jQuery源码分析-03构造jQuery对象-工具函数

    作者:nuysoft/高云 QQ:47214707 EMail:nuysoft@gmail.com 声明:本文为原创文章,如需转载,请注明来源并保留原文链接. 读读写写,不对的地方请告诉我,多多交流共同进步,本章的的PDF等本章写完了发布. jQuery源码分析系列的目录请查看 http://nuysoft.iteye.com/blog/1177451,想系统的好好写写,目前还是从我感兴趣的部分开始,如果大家有对哪个模块感兴趣的,建议优先分析的,可以告诉我,一起学习. 3.4 其他静态工具函数

  • Jquery1.9.1源码分析系列(十五)动画处理之外篇

    a.动画兼容Tween.propHooks Tween.propHooks提供特殊情况下设置.获取css特征值的方法,结构如下 Tween.propHooks = { _default: { get: function(){...}, set: function(){...} }, scrollTop: { set: function(){...} } scrollLeft: { set: function(){...} } } Tween.propHooks.scrollTop 和Tween.

  • jQuery 1.9.1源码分析系列(十四)之常用jQuery工具

    为了给下一章分析动画处理做准备,先来看一下一些工具.其中队列工具在动画处理中被经常使用. jQuery.fn. queue(([ queueName ] [, newQueue ]) || ([ queueName ,] callback ))(获取或设置当前匹配元素上待执行的函数队列. 如果当前jQuery对象匹配多个元素:获取队列时,只获取第一个匹配元素上的队列:设置队列(替换队列.追加函数)时,则为每个匹配元素都分别进行设置.如果需要移除并执行队列中的第一个函数,请使用dequeue()函

随机推荐