从上面的方案看,测试套件没办法完全做到独立运行,每个测试用例都是相对独立的,所以可以从定时任务执行时增加对应的逻辑
goroutine
,好在 go 协程实现非常简单,只要在函数前面增加go
就可以了,如:go func()
修改 hrp.Run 函数
func (r *HRPRunner) Run(testcases ...ITestCase) (interfacecase.ApiReport, error) {
// 省略部分代码
var runErr error
// run testcase one by one
var wg sync.WaitGroup
// 通过channel的缓冲区设置协程数,最小2,最大为cpu线程数-2
cpu := 2
if runtime.NumCPU() >= 4 {
cpu = runtime.NumCPU() - 2
}
intChan := make(chan int, cpu)
defer close(intChan)
// 添加计数器为用例个数
wg.Add(len(testcases))
for _, testCase := range testCases {
// each testcase has its own case runner
go func(testcase *TestCase) {
defer wg.Done()
intChan <- 1
defer func() {
<-intChan
}()
caseRunner, err := r.NewCaseRunner(testcase)
if err != nil {
log.Error().Err(err).Msg("[Run] init case runner failed")
return
}
// release UI driver session
defer func() {
for _, client := range r.uiClients {
client.Driver.DeleteSession()
}
}()
for it := caseRunner.parametersIterator; it.HasNext(); {
sessionRunner := caseRunner.NewSession()
err1 := sessionRunner.Start(it.Next())
if err1 != nil {
log.Error().Err(err1).Msg("[Run] run testcase failed")
runErr = err1
}
caseSummary, err2 := sessionRunner.GetSummary()
caseSummary.CaseID = testcase.ID
//for k, _ := range caseSummary.Records {
// caseSummary.Records[k].ValidatorsNumber = testcase.TestSteps[k].Struct().ValidatorsNumber
//}
//把header、Extract导出到上一级配置(caseRunner.testCase.Config)中
//caseRunner.testCase.Config
caseSummary.Name = testcase.Name
s.appendCaseSummary(caseSummary)
if err2 != nil {
log.Error().Err(err2).Msg("[Run] get summary failed")
if err1 != nil {
runErr = errors.Wrap(err1, err2.Error())
} else {
runErr = err2
}
}
}
}(testCase)
}
// 阻塞,等待运行结束
wg.Wait()
s.Time.Duration = time.Since(s.Time.StartAt).Seconds()
// save summary
if r.saveTests {
err := s.genSummary()
if err != nil {
return interfacecase.ApiReport{}, err
}
}
// 省略部分代码
}
按照 cpu 线程数 (i7 10700 8 核 16 线程)-2 进行执行,比单个运行时间节省了接近 90%,如果是全量回归,可以节省比较多的时间