Go-知识测试-子测试

07-14 1332阅读

Go-知识测试-子测试

  • 1. 介绍
  • 2. 例子
  • 3. 子测试命名规则
  • 4. 选择性执行
  • 5. 子测试并发
  • 6. testing.T.Run
  • 7. testing.T.Parallel
  • 8. 子测试适用于单元测试
  • 9. 子测试适用于性能测试
  • 10. 总结
    • 10.1 启动子测试 Run
    • 10.2 启动并发测试 Parallel

      建议先看:https://blog.csdn.net/a18792721831/article/details/140062769

      Go-知识测试-工作机制

      1. 介绍

      子测试提供了一种在一个测试函数中执行多个测试的能力,可以自己编排执行顺序,或者做一些初始化等操作。

      2. 例子

      比如如下代码:

      import "testing"
      func SubA(t *testing.T) {
      	t.Log("test A " + t.Name())
      }
      func SubB(t *testing.T) {
      	t.Log("test B " + t.Name())
      }
      func SubC(t *testing.T) {
      	t.Log("test C " + t.Name())
      }
      func TestSub(t *testing.T) {
      	t.Run("name=A", SubA)
      	t.Run("name=B", SubB)
      	t.Run("name=C", SubC)
      }
      

      使用go test -v xx_test.go执行

      Go-知识测试-子测试

      3. 子测试命名规则

      Run()方法的第一个参数作为子测试的名字,这里只是本层级的名字。

      实际上子测试的内部命名规则是: /

      比如我们在B里面在调用A:

      Go-知识测试-子测试

      执行后:

      Go-知识测试-子测试

      name具有传递性

      4. 选择性执行

      在上面我们有 name=A,name=B,name=C 三个测试,如果只是想执行A呢

      使用go test -v xx_test.go -run TestSub/name=A

      Go-知识测试-子测试

      选择性执行的字符串,是包含匹配,不是严格的正则匹配。

      Go-知识测试-子测试

      5. 子测试并发

      可以看到,前面的子测试都是根据代码顺序执行,串行执行,并没有并发。

      使用 t.Parallel 可以让当前测试函数允许并发。

      比如如下例子不加并发的时候:

      import (
      	"testing"
      	"time"
      )
      func SubA(t *testing.T) {
      	t.Log("test A " + t.Name())
      	time.Sleep(time.Second*3)
      }
      func SubB(t *testing.T) {
      	t.Log("test B " + t.Name())
      	time.Sleep(time.Second*2)
      }
      func SubC(t *testing.T) {
      	time.Sleep(time.Second*1)
      	t.Log("test C " + t.Name())
      }
      func TestSub(t *testing.T) {
      	t.Run("name=A", SubA)
      	t.Run("name=B", SubB)
      	t.Run("name=C", SubC)
      }
      

      执行后用时超过6秒

      Go-知识测试-子测试

      允许并发:

      import (
      	"testing"
      	"time"
      )
      func SubA(t *testing.T) {
      	t.Parallel()
      	t.Log("test A " + t.Name())
      	time.Sleep(time.Second * 3)
      }
      func SubB(t *testing.T) {
      	t.Parallel()
      	t.Log("test B " + t.Name())
      	time.Sleep(time.Second * 2)
      }
      func SubC(t *testing.T) {
      	t.Parallel()
      	time.Sleep(time.Second * 1)
      	t.Log("test C " + t.Name())
      }
      func TestSub(t *testing.T) {
      	t.Run("name=A", SubA)
      	t.Run("name=B", SubB)
      	t.Run("name=C", SubC)
      }
      

      Go-知识测试-子测试

      A最先被调度,但是确是最后执行完毕。

      需要注意的是,当开启子测试并发后,调用了子测试后,父测试的代码和子测试代码执行顺序就是随机的了。

      所以如果在主测试中需要做一些初始化,然后在执行子测试,那么需要注意,有可能初始化还未完成,子测试已经开始执行了。

      6. testing.T.Run

      // 将运行f作为名为name的t的子测试。它在一个单独的goroutine中运行f
      // 并且阻塞直到f返回或调用t。并行成为并行测试。
      // 运行报告f是否成功(或者至少在调用t.Parallel之前没有失败)。
      //
      // Run可以从多个goroutine同时调用,但所有此类调用
      // 必须在t的外部测试函数返回之前返回。
      func (t *T) Run(name string, f func(t *T)) bool {
      	atomic.StoreInt32(&t.hasSub, 1)
      	testName, ok, _ := t.context.match.fullName(&t.common, name)
      	if !ok || shouldFailFast() {
      		return true
      	}
      	//记录此调用点的堆栈跟踪,以便如果子测试
      	//在单独的堆栈中运行的函数被标记为助手,我们可以
      	//继续将堆栈遍历到父测试中。
      	var pc [maxStackLen]uintptr
      	n := runtime.Callers(2, pc[:])
      	t = &T{
      		common: common{
      			barrier: make(chan bool),
      			signal:  make(chan bool, 1),
      			name:    testName,
      			parent:  &t.common,
      			level:   t.level + 1,
      			creator: pc[:n],
      			chatty:  t.chatty,
      		},
      		context: t.context,
      	}
      	t.w = indenter{&t.common}
      	if t.chatty != nil {
      		t.chatty.Updatef(t.name, "=== RUN   %s\n", t.name)
      	}
      	//而不是在调用之前减少此测试的运行计数
      	//tRunner并在之后增加它,我们依靠tRunner保持
      	//计数正确。这样可以确保运行一系列顺序测试
      	//而不会被抢占,即使它们的父级是并行测试。这
      	//如果*parallel==1,则可以特别减少意外。
      	go tRunner(t, f)
      	if !
VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]