feat: data-driven.

This commit is contained in:
徐聪
2022-01-04 20:34:43 +08:00
parent 70cf171ee3
commit 6fd07a4388
6 changed files with 98 additions and 67 deletions
+4 -2
View File
@@ -76,8 +76,10 @@ func (b *hrpBoomer) convertBoomerTask(testcase *TestCase) *boomer.Task {
if err := copier.Copy(caseConfig, cfg); err != nil { if err := copier.Copy(caseConfig, cfg); err != nil {
log.Error().Err(err).Msg("copy config data failed") log.Error().Err(err).Msg("copy config data failed")
} }
if it := cfg.ParametersSetting.Iterator; it.HasNext() { for _, it := range cfg.ParametersSetting.Iterator {
caseConfig.Variables = mergeVariables(it.Next(), caseConfig.Variables) if it.HasNext() {
caseConfig.Variables = mergeVariables(it.Next(), caseConfig.Variables)
}
} }
startTime := time.Now() startTime := time.Now()
for index, step := range testcase.TestSteps { for index, step := range testcase.TestSteps {
+5 -2
View File
@@ -9,8 +9,11 @@
"username-password": "${parameterize(examples/account.csv)}" "username-password": "${parameterize(examples/account.csv)}"
}, },
"parameters_setting": { "parameters_setting": {
"strategy": "random", "strategy": [
"iteration": 1 "random",
"sequential"
],
"iteration": 10
}, },
"variables": { "variables": {
"app_version": "v1", "app_version": "v1",
+32 -33
View File
@@ -1,39 +1,38 @@
config: config:
name: "request methods testcase: validate with parameters" name: "request methods testcase: validate with parameters"
parameters: parameters:
user_agent: ["iOS/10.1", "iOS/10.2"] user_agent: [ "iOS/10.1", "iOS/10.2" ]
username-password: ${parameterize(examples/account.csv)} username-password: ${parameterize(examples/account.csv)}
parameters_setting: parameters_setting:
strategy: random strategy: ["random", "sequential"]
iteration: 1 iteration: 10
variables: variables:
app_version: v1 app_version: v1
user_agent: iOS/10.3 user_agent: iOS/10.3
base_url: "https://postman-echo.com" base_url: "https://postman-echo.com"
verify: False verify: False
teststeps: teststeps:
- - name: get with params
name: get with params
variables: variables:
foo1: $username foo1: $username
foo2: $password foo2: $password
foo3: $user_agent foo3: $user_agent
request: request:
method: GET method: GET
url: /get url: /get
params: params:
foo1: $foo1 foo1: $foo1
foo2: $foo2 foo2: $foo2
foo3: $foo3 foo3: $foo3
headers: headers:
User-Agent: $user_agent,$app_version User-Agent: $user_agent,$app_version
validate: validate:
- check: status_code - check: status_code
assert: equals assert: equals
expect: 200 expect: 200
msg: check status code msg: check status code
- check: body.args.foo3 - check: body.args.foo3
assert: not_equal assert: not_equal
expect: iOS/10.3 expect: iOS/10.3
msg: check app version msg: check app version
+4 -4
View File
@@ -30,9 +30,9 @@ type TConfig struct {
} }
type TParamsConfig struct { type TParamsConfig struct {
Strategy string `json:"strategy,omitempty" yaml:"strategy,omitempty"` Strategy interface{} `json:"strategy,omitempty" yaml:"strategy,omitempty"`
Iteration int `json:"iteration,omitempty" yaml:"iteration,omitempty"` Iteration int `json:"iteration,omitempty" yaml:"iteration,omitempty"`
Iterator *Iterator `json:"parameterIterator,omitempty" yaml:"parameterIterator,omitempty"` Iterator []*Iterator `json:"parameterIterator,omitempty" yaml:"parameterIterator,omitempty"`
} }
const ( const (
@@ -68,7 +68,6 @@ func (iter *Iterator) HasNext() bool {
func (iter *Iterator) Next() (value map[string]interface{}) { func (iter *Iterator) Next() (value map[string]interface{}) {
iter.Lock() iter.Lock()
defer iter.Unlock() defer iter.Unlock()
iter.index++
if len(iter.data) == 0 { if len(iter.data) == 0 {
return map[string]interface{}{} return map[string]interface{}{}
} }
@@ -79,6 +78,7 @@ func (iter *Iterator) Next() (value map[string]interface{}) {
} else { } else {
value = iter.data[iter.index%len(iter.data)] value = iter.data[iter.index%len(iter.data)]
} }
iter.index++
return value return value
} }
+47 -24
View File
@@ -494,14 +494,14 @@ func findallVariables(raw string) variableSet {
return varSet return varSet
} }
func genCartesianProduct(params [][]map[string]interface{}) []map[string]interface{} { func genCartesianProduct(params []paramsType) paramsType {
if len(params) == 0 { if len(params) == 0 {
return nil return nil
} }
var cartesianProduct []map[string]interface{} var cartesianProduct paramsType
cartesianProduct = params[0] cartesianProduct = params[0]
for i := 0; i < len(params)-1; i++ { for i := 0; i < len(params)-1; i++ {
var tempProduct []map[string]interface{} var tempProduct paramsType
for _, param1 := range cartesianProduct { for _, param1 := range cartesianProduct {
for _, param2 := range params[i+1] { for _, param2 := range params[i+1] {
tempProduct = append(tempProduct, mergeVariables(param1, param2)) tempProduct = append(tempProduct, mergeVariables(param1, param2))
@@ -512,14 +512,14 @@ func genCartesianProduct(params [][]map[string]interface{}) []map[string]interfa
return cartesianProduct return cartesianProduct
} }
func parseParameters(parameters map[string]interface{}, variablesMapping map[string]interface{}) ([]map[string]interface{}, error) { func parseParameters(parameters map[string]interface{}, variablesMapping map[string]interface{}) ([]paramsType, error) {
if len(parameters) == 0 { if len(parameters) == 0 {
return nil, nil return nil, nil
} }
var parsedParametersSlice [][]map[string]interface{} var parsedParametersSlice []paramsType
var err error var err error
for k, v := range parameters { for k, v := range parameters {
var parameterSlice []map[string]interface{} var parameterSlice paramsType
rawValue := reflect.ValueOf(v) rawValue := reflect.ValueOf(v)
switch rawValue.Kind() { switch rawValue.Kind() {
case reflect.String: case reflect.String:
@@ -548,7 +548,7 @@ func parseParameters(parameters map[string]interface{}, variablesMapping map[str
} }
parsedParametersSlice = append(parsedParametersSlice, parameterSlice) parsedParametersSlice = append(parsedParametersSlice, parameterSlice)
} }
return genCartesianProduct(parsedParametersSlice), nil return parsedParametersSlice, nil
} }
func parseSlice(parameterName string, parameterContent interface{}) ([]map[string]interface{}, error) { func parseSlice(parameterName string, parameterContent interface{}) ([]map[string]interface{}, error) {
@@ -599,31 +599,54 @@ func parseSlice(parameterName string, parameterContent interface{}) ([]map[strin
} }
func initParameterIterator(cfg *TConfig, mode string) (err error) { func initParameterIterator(cfg *TConfig, mode string) (err error) {
var parameters paramsType var parameters []paramsType
parameters, err = parseParameters(cfg.Parameters, cfg.Variables) parameters, err = parseParameters(cfg.Parameters, cfg.Variables)
// parse config parameters setting
if cfg.ParametersSetting == nil {
cfg.ParametersSetting = &TParamsConfig{Iterator: &Iterator{}}
}
cfg.ParametersSetting.Iterator = parameters.Iterator()
if err != nil { if err != nil {
return err return err
} }
if len(cfg.ParametersSetting.Strategy) == 0 { // parse config parameters setting
cfg.ParametersSetting.Strategy = strategySequential if cfg.ParametersSetting == nil {
} else { cfg.ParametersSetting = &TParamsConfig{Iterator: []*Iterator{}}
cfg.ParametersSetting.Strategy = strings.ToLower(cfg.ParametersSetting.Strategy)
} }
cfg.ParametersSetting.Iterator.strategy = cfg.ParametersSetting.Strategy
if mode == "boomer" { if mode == "boomer" {
cfg.ParametersSetting.Iteration = -1 cfg.ParametersSetting.Iteration = -1
cfg.ParametersSetting.Iterator.iteration = cfg.ParametersSetting.Iteration }
} else { rawValue := reflect.ValueOf(cfg.ParametersSetting.Strategy)
if cfg.ParametersSetting.Iteration > 0 { switch rawValue.Kind() {
cfg.ParametersSetting.Iterator.iteration = cfg.ParametersSetting.Iteration case reflect.String:
} else if cfg.ParametersSetting.Iterator.iteration == 0 { if len(rawValue.String()) == 0 {
cfg.ParametersSetting.Iterator.iteration = 1 cfg.ParametersSetting.Strategy = strategySequential
} else {
cfg.ParametersSetting.Strategy = strings.ToLower(rawValue.String())
}
cfg.ParametersSetting.Iterator = append(
cfg.ParametersSetting.Iterator,
newIterator(genCartesianProduct(parameters), cfg.ParametersSetting.Strategy.(string), cfg.ParametersSetting.Iteration),
)
case reflect.Slice:
if len(parameters) != rawValue.Len() {
return errors.New("parameters and strategy should have the same length")
} else {
for i := 0; i < rawValue.Len(); i++ {
cfg.ParametersSetting.Iterator = append(
cfg.ParametersSetting.Iterator,
newIterator(parameters[i], rawValue.Index(i).Interface().(string), cfg.ParametersSetting.Iteration),
)
}
} }
} }
return nil return nil
} }
func newIterator(parameters paramsType, strategy string, iteration int) *Iterator {
it := parameters.Iterator()
it.strategy = strategy
if iteration > 0 {
it.iteration = iteration
} else if it.iteration == 0 {
it.iteration = 1
} else {
it.iteration = -1
}
return it
}
+6 -2
View File
@@ -143,8 +143,12 @@ func (r *caseRunner) run() error {
} }
cfg := config.ToStruct() cfg := config.ToStruct()
log.Info().Str("testcase", config.Name()).Msg("run testcase start") log.Info().Str("testcase", config.Name()).Msg("run testcase start")
for it := cfg.ParametersSetting.Iterator; it.HasNext(); { for it := cfg.ParametersSetting.Iterator[0]; it.HasNext(); {
cfg.Variables = mergeVariables(it.Next(), cfg.Variables) for _, it = range cfg.ParametersSetting.Iterator {
if it.HasNext() {
cfg.Variables = mergeVariables(it.Next(), cfg.Variables)
}
}
r.startTime = time.Now() r.startTime = time.Now()
for index := range r.TestCase.TestSteps { for index := range r.TestCase.TestSteps {
_, err := r.runStep(index, cfg) _, err := r.runStep(index, cfg)