mirror of
https://github.com/httprunner/httprunner.git
synced 2026-06-06 16:29:37 +08:00
change: add unittests for init parameters iterator
This commit is contained in:
@@ -6,18 +6,19 @@
|
|||||||
"iOS/10.1",
|
"iOS/10.1",
|
||||||
"iOS/10.2"
|
"iOS/10.2"
|
||||||
],
|
],
|
||||||
"username-password": "${parameterize(examples/hrp/account.csv)}"
|
"username-password": "${parameterize($file)}"
|
||||||
},
|
},
|
||||||
"parameters_setting": {
|
"parameters_setting": {
|
||||||
"strategy": {
|
"strategies": {
|
||||||
"user_agent": "sequential",
|
"user_agent": "sequential",
|
||||||
"username-password": "random"
|
"username-password": "random"
|
||||||
},
|
},
|
||||||
"iteration": 6
|
"limit": 6
|
||||||
},
|
},
|
||||||
"variables": {
|
"variables": {
|
||||||
"app_version": "v1",
|
"app_version": "v1",
|
||||||
"user_agent": "iOS/10.3"
|
"user_agent": "iOS/10.3",
|
||||||
|
"file": "examples/hrp/account.csv"
|
||||||
},
|
},
|
||||||
"base_url": "https://postman-echo.com",
|
"base_url": "https://postman-echo.com",
|
||||||
"verify": false
|
"verify": false
|
||||||
|
|||||||
@@ -2,15 +2,16 @@ 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/hrp/account.csv)}
|
username-password: ${parameterize($file)}
|
||||||
parameters_setting:
|
parameters_setting:
|
||||||
strategy:
|
strategies:
|
||||||
user_agent: "sequential"
|
user_agent: "sequential"
|
||||||
username-password: "random"
|
username-password: "random"
|
||||||
iteration: 6
|
limit: 6
|
||||||
variables:
|
variables:
|
||||||
app_version: v1
|
app_version: v1
|
||||||
user_agent: iOS/10.3
|
user_agent: iOS/10.3
|
||||||
|
file: examples/hrp/account.csv
|
||||||
base_url: "https://postman-echo.com"
|
base_url: "https://postman-echo.com"
|
||||||
verify: False
|
verify: False
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ func initParametersIterator(cfg *TConfig) (*ParametersIterator, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newParametersIterator(parameters map[string]Parameters, config *TParamsConfig) *ParametersIterator {
|
func newParametersIterator(parameters map[string]Parameters, config *TParamsConfig) *ParametersIterator {
|
||||||
|
if config == nil {
|
||||||
|
config = &TParamsConfig{}
|
||||||
|
}
|
||||||
iterator := &ParametersIterator{
|
iterator := &ParametersIterator{
|
||||||
data: parameters,
|
data: parameters,
|
||||||
hasNext: true,
|
hasNext: true,
|
||||||
@@ -52,7 +55,8 @@ func newParametersIterator(parameters map[string]Parameters, config *TParamsConf
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(parameters) == 0 {
|
if len(parameters) == 0 {
|
||||||
iterator.hasNext = false
|
iterator.data = map[string]Parameters{}
|
||||||
|
iterator.limit = 1
|
||||||
return iterator
|
return iterator
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,12 +79,23 @@ func newParametersIterator(parameters map[string]Parameters, config *TParamsConf
|
|||||||
|
|
||||||
// generate cartesian product for sequential parameters
|
// generate cartesian product for sequential parameters
|
||||||
iterator.sequentialParameters = genCartesianProduct(parametersList)
|
iterator.sequentialParameters = genCartesianProduct(parametersList)
|
||||||
|
|
||||||
|
if iterator.limit < 0 {
|
||||||
|
log.Warn().Msg("parameters unlimited mode is only supported for load testing")
|
||||||
|
iterator.limit = 0
|
||||||
|
}
|
||||||
if iterator.limit == 0 {
|
if iterator.limit == 0 {
|
||||||
|
// limit not set
|
||||||
if len(iterator.sequentialParameters) > 0 {
|
if len(iterator.sequentialParameters) > 0 {
|
||||||
|
// use cartesian product of sequential parameters size as limit
|
||||||
iterator.limit = len(iterator.sequentialParameters)
|
iterator.limit = len(iterator.sequentialParameters)
|
||||||
} else {
|
} else {
|
||||||
|
// all parameters are selected by random
|
||||||
|
// only run once
|
||||||
iterator.limit = 1
|
iterator.limit = 1
|
||||||
}
|
}
|
||||||
|
} else { // limit > 0
|
||||||
|
log.Info().Int("limit", iterator.limit).Msg("set limit for parameters")
|
||||||
}
|
}
|
||||||
|
|
||||||
return iterator
|
return iterator
|
||||||
@@ -98,6 +113,7 @@ type ParametersIterator struct {
|
|||||||
|
|
||||||
// SetUnlimitedMode is used for load testing
|
// SetUnlimitedMode is used for load testing
|
||||||
func (iter *ParametersIterator) SetUnlimitedMode() {
|
func (iter *ParametersIterator) SetUnlimitedMode() {
|
||||||
|
log.Info().Msg("set parameters unlimited mode")
|
||||||
iter.limit = -1
|
iter.limit = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,15 +150,24 @@ func (iter *ParametersIterator) Next() map[string]interface{} {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedParameters := make(map[string]interface{})
|
var selectedParameters map[string]interface{}
|
||||||
if iter.index < len(iter.sequentialParameters) {
|
if len(iter.sequentialParameters) == 0 {
|
||||||
|
selectedParameters = make(map[string]interface{})
|
||||||
|
} else if iter.index < len(iter.sequentialParameters) {
|
||||||
selectedParameters = iter.sequentialParameters[iter.index]
|
selectedParameters = iter.sequentialParameters[iter.index]
|
||||||
|
} else {
|
||||||
|
// loop back to the first sequential parameter
|
||||||
|
index := iter.index % len(iter.sequentialParameters)
|
||||||
|
selectedParameters = iter.sequentialParameters[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// merge with random parameters
|
||||||
for _, paramName := range iter.randomParameterNames {
|
for _, paramName := range iter.randomParameterNames {
|
||||||
randSource := rand.New(rand.NewSource(time.Now().Unix()))
|
randSource := rand.New(rand.NewSource(time.Now().Unix()))
|
||||||
randIndex := randSource.Intn(len(iter.data[paramName]))
|
randIndex := randSource.Intn(len(iter.data[paramName]))
|
||||||
selectedParameters[paramName] = iter.data[paramName][randIndex]
|
for k, v := range iter.data[paramName][randIndex] {
|
||||||
|
selectedParameters[k] = v
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iter.index++
|
iter.index++
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -31,7 +30,7 @@ func TestLoadParameters(t *testing.T) {
|
|||||||
{"test1", "111111"},
|
{"test1", "111111"},
|
||||||
{"test2", "222222"},
|
{"test2", "222222"},
|
||||||
},
|
},
|
||||||
"user_agent": []interface{}{"IOS/10.1", "IOS/10.2"},
|
"user_agent": []interface{}{"iOS/10.1", "iOS/10.2"},
|
||||||
"app_version": []interface{}{4.0},
|
"app_version": []interface{}{4.0},
|
||||||
},
|
},
|
||||||
map[string]Parameters{
|
map[string]Parameters{
|
||||||
@@ -40,8 +39,8 @@ func TestLoadParameters(t *testing.T) {
|
|||||||
{"username": "test2", "password": "222222"},
|
{"username": "test2", "password": "222222"},
|
||||||
},
|
},
|
||||||
"user_agent": {
|
"user_agent": {
|
||||||
{"user_agent": "IOS/10.1"},
|
{"user_agent": "iOS/10.1"},
|
||||||
{"user_agent": "IOS/10.2"},
|
{"user_agent": "iOS/10.2"},
|
||||||
},
|
},
|
||||||
"app_version": {
|
"app_version": {
|
||||||
{"app_version": 4.0},
|
{"app_version": 4.0},
|
||||||
@@ -79,17 +78,17 @@ func TestLoadParametersError(t *testing.T) {
|
|||||||
{
|
{
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"username_password": fmt.Sprintf("${parameterize(%s/account.csv)}", hrpExamplesDir),
|
"username_password": fmt.Sprintf("${parameterize(%s/account.csv)}", hrpExamplesDir),
|
||||||
"user_agent": []interface{}{"IOS/10.1", "IOS/10.2"}},
|
"user_agent": []interface{}{"iOS/10.1", "iOS/10.2"}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"username-password": fmt.Sprintf("${parameterize(%s/account.csv)}", hrpExamplesDir),
|
"username-password": fmt.Sprintf("${parameterize(%s/account.csv)}", hrpExamplesDir),
|
||||||
"user-agent": []interface{}{"IOS/10.1", "IOS/10.2"}},
|
"user-agent": []interface{}{"iOS/10.1", "iOS/10.2"}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"username-password": fmt.Sprintf("${param(%s/account.csv)}", hrpExamplesDir),
|
"username-password": fmt.Sprintf("${param(%s/account.csv)}", hrpExamplesDir),
|
||||||
"user_agent": []interface{}{"IOS/10.1", "IOS/10.2"}},
|
"user_agent": []interface{}{"iOS/10.1", "iOS/10.2"}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, data := range testData {
|
for _, data := range testData {
|
||||||
@@ -100,23 +99,69 @@ func TestLoadParametersError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInitParametersIterator(t *testing.T) {
|
func TestInitParametersIteratorCount(t *testing.T) {
|
||||||
configParameters := map[string]interface{}{
|
configParameters := map[string]interface{}{
|
||||||
"username-password": fmt.Sprintf("${parameterize(%s/account.csv)}", hrpExamplesDir), // 3
|
"username-password": fmt.Sprintf("${parameterize(%s/account.csv)}", hrpExamplesDir), // 3
|
||||||
"user_agent": []interface{}{"IOS/10.1", "IOS/10.2"},
|
"user_agent": []interface{}{"iOS/10.1", "iOS/10.2"}, // 2
|
||||||
"app_version": []interface{}{4.0},
|
"app_version": []interface{}{4.0}, // 1
|
||||||
}
|
}
|
||||||
testData := []struct {
|
testData := []struct {
|
||||||
cfg *TConfig
|
cfg *TConfig
|
||||||
expectLimit int
|
expectLimit int
|
||||||
}{
|
}{
|
||||||
|
// default, no parameters setting
|
||||||
{
|
{
|
||||||
&TConfig{
|
&TConfig{
|
||||||
Parameters: configParameters,
|
Parameters: configParameters,
|
||||||
ParametersSetting: &TParamsConfig{},
|
ParametersSetting: &TParamsConfig{},
|
||||||
},
|
},
|
||||||
6,
|
6, // 3 * 2 * 1
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
&TConfig{
|
||||||
|
Parameters: configParameters,
|
||||||
|
},
|
||||||
|
6, // 3 * 2 * 1
|
||||||
|
},
|
||||||
|
// default equals to set overall parameters strategy to "sequential"
|
||||||
|
{
|
||||||
|
&TConfig{
|
||||||
|
Parameters: configParameters,
|
||||||
|
ParametersSetting: &TParamsConfig{
|
||||||
|
Strategy: "sequential",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
6, // 3 * 2 * 1
|
||||||
|
},
|
||||||
|
// default equals to set each individual parameters strategy to "sequential"
|
||||||
|
{
|
||||||
|
&TConfig{
|
||||||
|
Parameters: configParameters,
|
||||||
|
ParametersSetting: &TParamsConfig{
|
||||||
|
Strategies: map[string]iteratorStrategy{
|
||||||
|
"username-password": "sequential",
|
||||||
|
"user_agent": "sequential",
|
||||||
|
"app_version": "sequential",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
6, // 3 * 2 * 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&TConfig{
|
||||||
|
Parameters: configParameters,
|
||||||
|
ParametersSetting: &TParamsConfig{
|
||||||
|
Strategies: map[string]iteratorStrategy{
|
||||||
|
"user_agent": "sequential",
|
||||||
|
"app_version": "sequential",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
6, // 3 * 2 * 1
|
||||||
|
},
|
||||||
|
|
||||||
|
// set overall parameters overall strategy to "random"
|
||||||
|
// each random parameters only select one item
|
||||||
{
|
{
|
||||||
&TConfig{
|
&TConfig{
|
||||||
Parameters: configParameters,
|
Parameters: configParameters,
|
||||||
@@ -124,7 +169,20 @@ func TestInitParametersIterator(t *testing.T) {
|
|||||||
Strategy: "random",
|
Strategy: "random",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
1,
|
1, // 1 * 1 * 1
|
||||||
|
},
|
||||||
|
// set some individual parameters strategy to "random"
|
||||||
|
// this will override overall strategy
|
||||||
|
{
|
||||||
|
&TConfig{
|
||||||
|
Parameters: configParameters,
|
||||||
|
ParametersSetting: &TParamsConfig{
|
||||||
|
Strategies: map[string]iteratorStrategy{
|
||||||
|
"user_agent": "random",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
3, // 3 * 1 * 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
&TConfig{
|
&TConfig{
|
||||||
@@ -135,7 +193,37 @@ func TestInitParametersIterator(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
2,
|
2, // 1 * 2 * 1
|
||||||
|
},
|
||||||
|
|
||||||
|
// set limit for parameters
|
||||||
|
{
|
||||||
|
&TConfig{
|
||||||
|
Parameters: configParameters, // total: 6 = 3 * 2 * 1
|
||||||
|
ParametersSetting: &TParamsConfig{
|
||||||
|
Limit: 4, // limit could be less than total
|
||||||
|
},
|
||||||
|
},
|
||||||
|
4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&TConfig{
|
||||||
|
Parameters: configParameters, // total: 6 = 3 * 2 * 1
|
||||||
|
ParametersSetting: &TParamsConfig{
|
||||||
|
Limit: 9, // limit could also be greater than total
|
||||||
|
},
|
||||||
|
},
|
||||||
|
9,
|
||||||
|
},
|
||||||
|
|
||||||
|
// no parameters
|
||||||
|
// also will generate one empty item
|
||||||
|
{
|
||||||
|
&TConfig{
|
||||||
|
Parameters: nil,
|
||||||
|
ParametersSetting: nil,
|
||||||
|
},
|
||||||
|
1,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, data := range testData {
|
for _, data := range testData {
|
||||||
@@ -151,7 +239,7 @@ func TestInitParametersIterator(t *testing.T) {
|
|||||||
if !assert.True(t, iterator.HasNext()) {
|
if !assert.True(t, iterator.HasNext()) {
|
||||||
t.Fatal()
|
t.Fatal()
|
||||||
}
|
}
|
||||||
log.Info().Interface("next", iterator.Next()).Msg("get next parameters")
|
iterator.Next() // consume next parameters
|
||||||
}
|
}
|
||||||
// should not have next
|
// should not have next
|
||||||
if !assert.False(t, iterator.HasNext()) {
|
if !assert.False(t, iterator.HasNext()) {
|
||||||
@@ -160,6 +248,82 @@ func TestInitParametersIterator(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInitParametersIteratorContent(t *testing.T) {
|
||||||
|
configParameters := map[string]interface{}{
|
||||||
|
"username-password": fmt.Sprintf("${parameterize(%s/account.csv)}", hrpExamplesDir), // 3
|
||||||
|
"user_agent": []interface{}{"iOS/10.1", "iOS/10.2"}, // 2
|
||||||
|
"app_version": []interface{}{4.0}, // 1
|
||||||
|
}
|
||||||
|
testData := []struct {
|
||||||
|
cfg *TConfig
|
||||||
|
checkIndex int
|
||||||
|
expectParameters map[string]interface{}
|
||||||
|
}{
|
||||||
|
// default, no parameters setting
|
||||||
|
{
|
||||||
|
&TConfig{
|
||||||
|
Parameters: configParameters,
|
||||||
|
},
|
||||||
|
0, // check first item
|
||||||
|
map[string]interface{}{
|
||||||
|
"username": "test1", "password": "111111", "user_agent": "iOS/10.1", "app_version": 4.0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// set limit for parameters
|
||||||
|
{
|
||||||
|
&TConfig{
|
||||||
|
Parameters: map[string]interface{}{
|
||||||
|
"username-password": []map[string]interface{}{ // 1
|
||||||
|
{"username": "test1", "password": 111111, "other": "111"},
|
||||||
|
},
|
||||||
|
"user_agent": []string{"iOS/10.1", "iOS/10.2"}, // 2
|
||||||
|
},
|
||||||
|
ParametersSetting: &TParamsConfig{
|
||||||
|
Limit: 5, // limit could also be greater than total
|
||||||
|
Strategies: map[string]iteratorStrategy{
|
||||||
|
"username-password": "random",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
2, // check 3th item, equals to the first item
|
||||||
|
map[string]interface{}{
|
||||||
|
"username": "test1", "password": 111111, "user_agent": "iOS/10.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// no parameters
|
||||||
|
// also will generate one empty item
|
||||||
|
{
|
||||||
|
&TConfig{
|
||||||
|
Parameters: nil,
|
||||||
|
ParametersSetting: nil,
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
map[string]interface{}(nil),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, data := range testData {
|
||||||
|
iterator, err := initParametersIterator(data.cfg)
|
||||||
|
if !assert.Nil(t, err) {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
|
||||||
|
// get expected parameters item
|
||||||
|
for i := 0; i < data.checkIndex; i++ {
|
||||||
|
if !assert.True(t, iterator.HasNext()) {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
iterator.Next() // consume next parameters
|
||||||
|
}
|
||||||
|
parametersItem := iterator.Next()
|
||||||
|
|
||||||
|
if !assert.Equal(t, data.expectParameters, parametersItem) {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGenCartesianProduct(t *testing.T) {
|
func TestGenCartesianProduct(t *testing.T) {
|
||||||
testData := []struct {
|
testData := []struct {
|
||||||
multiParameters []Parameters
|
multiParameters []Parameters
|
||||||
|
|||||||
@@ -111,8 +111,13 @@ func (r *SessionRunner) MergeStepVariables(vars map[string]interface{}) (map[str
|
|||||||
|
|
||||||
// updateConfigVariables updates config variables with given variables.
|
// updateConfigVariables updates config variables with given variables.
|
||||||
// this is used for data driven
|
// this is used for data driven
|
||||||
func (r *SessionRunner) updateConfigVariables(givenVars map[string]interface{}) {
|
func (r *SessionRunner) updateConfigVariables(parameters map[string]interface{}) {
|
||||||
for k, v := range givenVars {
|
if parameters == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info().Interface("parameters", parameters).Msg("update config variables")
|
||||||
|
for k, v := range parameters {
|
||||||
r.parsedConfig.Variables[k] = v
|
r.parsedConfig.Variables[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user