mirror of
https://github.com/httprunner/httprunner.git
synced 2026-06-09 17:59:36 +08:00
docs: add docs for IStep
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
- change: integrate [sentry sdk][sentry sdk] for panic reporting and analysis
|
- change: integrate [sentry sdk][sentry sdk] for panic reporting and analysis
|
||||||
- change: lock funplugin version when creating scaffold project
|
- change: lock funplugin version when creating scaffold project
|
||||||
- fix: call referenced api/testcase with relative path
|
- fix: call referenced api/testcase with relative path
|
||||||
|
- refactor: redesign `IStep` to make step extensible to support implementing new protocols and test types
|
||||||
|
|
||||||
**python version**
|
**python version**
|
||||||
|
|
||||||
|
|||||||
95
docs/dev.md
Normal file
95
docs/dev.md
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
|
||||||
|
## 核心数据结构
|
||||||
|
|
||||||
|
HttpRunner 以 `TestCase` 为核心,将任意测试场景抽象为有序步骤的集合。
|
||||||
|
|
||||||
|
```go
|
||||||
|
type TestCase struct {
|
||||||
|
Config *TConfig
|
||||||
|
TestSteps []IStep
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
其中,测试步骤 `IStep` 采用了 `go interface` 的设计理念,支持进行任意拓展;步骤内容统一在 `Run` 方法中进行实现。
|
||||||
|
|
||||||
|
```go
|
||||||
|
type IStep interface {
|
||||||
|
Name() string
|
||||||
|
Type() StepType
|
||||||
|
Struct() *TStep
|
||||||
|
Run(*SessionRunner) (*StepResult, error)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
我们只需遵循 `IStep` 的接口定义,即可实现各种类型的测试步骤类型。当前已支持的步骤类型包括:
|
||||||
|
|
||||||
|
- request:发起单次 HTTP 请求
|
||||||
|
- api:引用执行其它 API 文件
|
||||||
|
- testcase:引用执行其它测试用例文件
|
||||||
|
- thinktime:思考时间,按照配置的逻辑进行等待
|
||||||
|
- transaction:事务机制,用于压测
|
||||||
|
- rendezvous:集合点机制,用于压测
|
||||||
|
|
||||||
|
基于该机制,我们可以扩展支持新的协议类型,例如 HTTP2/WebSocket/RPC 等;同时也可以支持新的测试类型,例如 UI 自动化。甚至我们还可以在一个测试用例中混合调用多种不同的 Step 类型,例如实现 HTTP/RPC/UI 混合场景。
|
||||||
|
|
||||||
|
## 运行主流程
|
||||||
|
|
||||||
|
### 整体控制器 HRPRunner
|
||||||
|
|
||||||
|
执行接口测试时,会初始化一个 `HRPRunner`,用于控制测试的执行策略。
|
||||||
|
|
||||||
|
```go
|
||||||
|
type HRPRunner struct {
|
||||||
|
t *testing.T
|
||||||
|
failfast bool
|
||||||
|
requestsLogOn bool
|
||||||
|
pluginLogOn bool
|
||||||
|
saveTests bool
|
||||||
|
genHTMLReport bool
|
||||||
|
client *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HRPRunner) Run(testcases ...ITestCase) error
|
||||||
|
func (r *HRPRunner) NewSessionRunner(testcase *TestCase) *SessionRunner
|
||||||
|
```
|
||||||
|
|
||||||
|
重点关注两个方法:
|
||||||
|
|
||||||
|
- Run:测试执行的主入口,支持运行一个或多个测试用例
|
||||||
|
- NewSessionRunner:针对给定的测试用例初始化一个 SessionRunner
|
||||||
|
|
||||||
|
### 用例执行器 SessionRunner
|
||||||
|
|
||||||
|
测试用例的具体执行都由 `SessionRunner` 完成,每个 TestCase 对应一个实例,在该实例中除了包含测试用例自身内容外,还会包含测试过程的 session 数据和最终测试结果 summary。
|
||||||
|
|
||||||
|
```go
|
||||||
|
type SessionRunner struct {
|
||||||
|
testCase *TestCase
|
||||||
|
hrpRunner *HRPRunner
|
||||||
|
parser *Parser
|
||||||
|
sessionVariables map[string]interface{}
|
||||||
|
transactions map[string]map[transactionType]time.Time
|
||||||
|
startTime time.Time // record start time of the testcase
|
||||||
|
summary *TestCaseSummary // record test case summary
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
重点关注一个方法:
|
||||||
|
|
||||||
|
- Start:启动执行用例,依次执行所有测试步骤
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *SessionRunner) Start() error {
|
||||||
|
...
|
||||||
|
// run step in sequential order
|
||||||
|
for _, step := range r.testCase.TestSteps {
|
||||||
|
_, err := step.Run(r)
|
||||||
|
if err != nil && r.hrpRunner.failfast {
|
||||||
|
return errors.Wrap(err, "abort running due to failfast setting")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
在主流程中,SessionRunner 并不需要关注 step 的具体类型,统一都是调用 `step.Run(r)`,具体实现逻辑都在对应 step 的 `Run(*SessionRunner)` 方法中。
|
||||||
@@ -147,7 +147,7 @@ func (b *HRPBoomer) convertBoomerTask(testcase *TestCase, rendezvousList []*Rend
|
|||||||
if stepResult.StepType == stepTypeTransaction {
|
if stepResult.StepType == stepTypeTransaction {
|
||||||
// transaction
|
// transaction
|
||||||
// FIXME: support nested transactions
|
// FIXME: support nested transactions
|
||||||
if step.ToStruct().Transaction.Type == transactionEnd { // only record when transaction ends
|
if step.Struct().Transaction.Type == transactionEnd { // only record when transaction ends
|
||||||
b.RecordTransaction(stepResult.Name, transactionSuccess, stepResult.Elapsed, 0)
|
b.RecordTransaction(stepResult.Name, transactionSuccess, stepResult.Elapsed, 0)
|
||||||
transactionSuccess = true // reset flag for next transaction
|
transactionSuccess = true // reset flag for next transaction
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,6 @@ type TStep struct {
|
|||||||
type IStep interface {
|
type IStep interface {
|
||||||
Name() string
|
Name() string
|
||||||
Type() StepType
|
Type() StepType
|
||||||
ToStruct() *TStep
|
Struct() *TStep
|
||||||
Run(*SessionRunner) (*StepResult, error)
|
Run(*SessionRunner) (*StepResult, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ func (s *StepAPIWithOptionalArgs) Type() StepType {
|
|||||||
return stepTypeAPI
|
return stepTypeAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepAPIWithOptionalArgs) ToStruct() *TStep {
|
func (s *StepAPIWithOptionalArgs) Struct() *TStep {
|
||||||
return s.step
|
return s.step
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ func (s *StepRendezvous) Type() StepType {
|
|||||||
return stepTypeRendezvous
|
return stepTypeRendezvous
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepRendezvous) ToStruct() *TStep {
|
func (s *StepRendezvous) Struct() *TStep {
|
||||||
return s.step
|
return s.step
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -703,7 +703,7 @@ func (s *StepRequestWithOptionalArgs) Type() StepType {
|
|||||||
return StepType(fmt.Sprintf("request-%v", s.step.Request.Method))
|
return StepType(fmt.Sprintf("request-%v", s.step.Request.Method))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepRequestWithOptionalArgs) ToStruct() *TStep {
|
func (s *StepRequestWithOptionalArgs) Struct() *TStep {
|
||||||
return s.step
|
return s.step
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -737,7 +737,7 @@ func (s *StepRequestExtraction) Type() StepType {
|
|||||||
return StepType(fmt.Sprintf("request-%v", s.step.Request.Method))
|
return StepType(fmt.Sprintf("request-%v", s.step.Request.Method))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepRequestExtraction) ToStruct() *TStep {
|
func (s *StepRequestExtraction) Struct() *TStep {
|
||||||
return s.step
|
return s.step
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -761,7 +761,7 @@ func (s *StepRequestValidation) Type() StepType {
|
|||||||
return StepType(fmt.Sprintf("request-%v", s.step.Request.Method))
|
return StepType(fmt.Sprintf("request-%v", s.step.Request.Method))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepRequestValidation) ToStruct() *TStep {
|
func (s *StepRequestValidation) Struct() *TStep {
|
||||||
return s.step
|
return s.step
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func (s *StepTestCaseWithOptionalArgs) Type() StepType {
|
|||||||
return stepTypeTestCase
|
return stepTypeTestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepTestCaseWithOptionalArgs) ToStruct() *TStep {
|
func (s *StepTestCaseWithOptionalArgs) Struct() *TStep {
|
||||||
return s.step
|
return s.step
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ func (s *StepThinkTime) Type() StepType {
|
|||||||
return stepTypeThinkTime
|
return stepTypeThinkTime
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepThinkTime) ToStruct() *TStep {
|
func (s *StepThinkTime) Struct() *TStep {
|
||||||
return s.step
|
return s.step
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func (s *StepTransaction) Type() StepType {
|
|||||||
return stepTypeTransaction
|
return stepTypeTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepTransaction) ToStruct() *TStep {
|
func (s *StepTransaction) Struct() *TStep {
|
||||||
return s.step
|
return s.step
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func (tc *TestCase) ToTCase() *TCase {
|
|||||||
Config: tc.Config,
|
Config: tc.Config,
|
||||||
}
|
}
|
||||||
for _, step := range tc.TestSteps {
|
for _, step := range tc.TestSteps {
|
||||||
tCase.TestSteps = append(tCase.TestSteps, step.ToStruct())
|
tCase.TestSteps = append(tCase.TestSteps, step.Struct())
|
||||||
}
|
}
|
||||||
return tCase
|
return tCase
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user