refactor: move tests

This commit is contained in:
lilong.129
2025-03-05 11:45:59 +08:00
parent e107389d6e
commit b9db874f38
25 changed files with 617 additions and 604 deletions

45
tests/build_test.go Normal file
View File

@@ -0,0 +1,45 @@
package tests
import (
"path/filepath"
"regexp"
"testing"
"github.com/stretchr/testify/assert"
hrp "github.com/httprunner/httprunner/v5"
"github.com/httprunner/httprunner/v5/internal/builtin"
)
func TestRun(t *testing.T) {
err := hrp.BuildPlugin(tmpl("plugin/debugtalk.go"), "./debugtalk.bin")
if !assert.Nil(t, err) {
t.Fatal()
}
genDebugTalkPyPath := filepath.Join(tmpl("plugin/"), hrp.PluginPySourceGenFile)
err = hrp.BuildPlugin(tmpl("plugin/debugtalk.py"), genDebugTalkPyPath)
if !assert.Nil(t, err) {
t.Fatal()
}
contentBytes, err := builtin.LoadFile(genDebugTalkPyPath)
if !assert.Nil(t, err) {
t.Fatal()
}
content := string(contentBytes)
if !assert.Contains(t, content, "import funppy") {
t.Fatal()
}
if !assert.Contains(t, content, "funppy.register") {
t.Fatal()
}
reg, _ := regexp.Compile(`funppy\.register`)
matchedSlice := reg.FindAllStringSubmatch(content, -1)
if !assert.Len(t, matchedSlice, 10) {
t.Fatal()
}
}

96
tests/loader_test.go Normal file
View File

@@ -0,0 +1,96 @@
package tests
import (
"testing"
"github.com/stretchr/testify/assert"
hrp "github.com/httprunner/httprunner/v5"
)
func TestLoadTestCases(t *testing.T) {
// load test cases from folder path
tc := hrp.TestCasePath("../examples/demo-with-py-plugin/testcases/")
testCases, err := hrp.LoadTestCases(&tc)
if !assert.Nil(t, err) {
t.Fatal()
}
if !assert.Equal(t, 4, len(testCases)) {
t.Fatal()
}
// load test cases from folder path, including sub folders
tc = hrp.TestCasePath("../examples/demo-with-py-plugin/")
testCases, err = hrp.LoadTestCases(&tc)
if !assert.Nil(t, err) {
t.Fatal()
}
if !assert.Equal(t, 4, len(testCases)) {
t.Fatal()
}
// load test cases from single file path
tc = hrp.TestCasePath(demoTestCaseWithPluginJSONPath)
testCases, err = hrp.LoadTestCases(&tc)
if !assert.Nil(t, err) {
t.Fatal()
}
if !assert.Equal(t, 1, len(testCases)) {
t.Fatal()
}
// load test cases from TestCase instance
testcase := &hrp.TestCase{
Config: hrp.NewConfig("TestCase").SetWeight(3),
}
testCases, err = hrp.LoadTestCases(testcase)
if !assert.Nil(t, err) {
t.Fatal()
}
if !assert.Equal(t, len(testCases), 1) {
t.Fatal()
}
// load test cases from TestCaseJSON
testcaseJSON := hrp.TestCaseJSON(`
{
"config":{"name":"TestCaseJSON"},
"teststeps":[
{"name": "step1", "request":{"url": "https://httpbin.org/get"}},
{"name": "step2", "shell":{"string": "ls -l"}}
]
}`)
testCases, err = hrp.LoadTestCases(&testcaseJSON)
if !assert.Nil(t, err) {
t.Fatal()
}
if !assert.Equal(t, len(testCases), 1) {
t.Fatal()
}
}
func TestLoadCase(t *testing.T) {
tcJSON := &hrp.TestCaseDef{}
tcYAML := &hrp.TestCaseDef{}
err := hrp.LoadFileObject(demoTestCaseWithPluginJSONPath, tcJSON)
if !assert.NoError(t, err) {
t.Fatal()
}
err = hrp.LoadFileObject(demoTestCaseWithPluginYAMLPath, tcYAML)
if !assert.NoError(t, err) {
t.Fatal()
}
if !assert.Equal(t, tcJSON.Config.Name, tcYAML.Config.Name) {
t.Fatal()
}
if !assert.Equal(t, tcJSON.Config.BaseURL, tcYAML.Config.BaseURL) {
t.Fatal()
}
if !assert.Equal(t, tcJSON.Steps[1].StepName, tcYAML.Steps[1].StepName) {
t.Fatal()
}
if !assert.Equal(t, tcJSON.Steps[1].Request, tcJSON.Steps[1].Request) {
t.Fatal()
}
}

540
tests/parameters_test.go Normal file
View File

@@ -0,0 +1,540 @@
package tests
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
hrp "github.com/httprunner/httprunner/v5"
)
func TestLoadParameters(t *testing.T) {
testData := []struct {
configParameters map[string]interface{}
loadedParameters map[string]hrp.Parameters
}{
{
map[string]interface{}{
"username-password": fmt.Sprintf("${parameterize(%s/$file)}", hrpExamplesDir),
},
map[string]hrp.Parameters{
"username-password": {
{"username": "test1", "password": "111111"},
{"username": "test2", "password": "222222"},
{"username": "test3", "password": "333333"},
},
},
},
{
map[string]interface{}{
"username-password": [][]interface{}{
{"test1", "111111"},
{"test2", "222222"},
},
"user_agent": []interface{}{"iOS/10.1", "iOS/10.2"},
"app_version": []interface{}{4.0},
},
map[string]hrp.Parameters{
"username-password": {
{"username": "test1", "password": "111111"},
{"username": "test2", "password": "222222"},
},
"user_agent": {
{"user_agent": "iOS/10.1"},
{"user_agent": "iOS/10.2"},
},
"app_version": {
{"app_version": 4.0},
},
},
},
{
map[string]interface{}{
"username-password": []interface{}{
[]interface{}{"test1", "111111"},
[]interface{}{"test2", "222222"},
},
},
map[string]hrp.Parameters{
"username-password": {
{"username": "test1", "password": "111111"},
{"username": "test2", "password": "222222"},
},
},
},
{
map[string]interface{}{},
nil,
},
{
nil,
nil,
},
}
variablesMapping := map[string]interface{}{
"file": "account.csv",
}
parser := hrp.NewParser()
for _, data := range testData {
value, err := parser.LoadParameters(data.configParameters, variablesMapping)
if !assert.Nil(t, err) {
t.Fatal()
}
if !assert.Equal(t, data.loadedParameters, value) {
t.Fatal()
}
}
}
func TestLoadParametersError(t *testing.T) {
testData := []struct {
configParameters map[string]interface{}
}{
{
map[string]interface{}{
"username_password": fmt.Sprintf("${parameterize(%s/account.csv)}", hrpExamplesDir),
"user_agent": []interface{}{"iOS/10.1", "iOS/10.2"},
},
},
{
map[string]interface{}{
"username-password": fmt.Sprintf("${parameterize(%s/account.csv)}", hrpExamplesDir),
"user-agent": []interface{}{"iOS/10.1", "iOS/10.2"},
},
},
{
map[string]interface{}{
"username-password": fmt.Sprintf("${param(%s/account.csv)}", hrpExamplesDir),
"user_agent": []interface{}{"iOS/10.1", "iOS/10.2"},
},
},
}
parser := hrp.NewParser()
for _, data := range testData {
_, err := parser.LoadParameters(data.configParameters, map[string]interface{}{})
if !assert.Error(t, err) {
t.Fatal()
}
}
}
func TestInitParametersIteratorCount(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 *hrp.TConfig
expectLimit int
}{
// default, no parameters setting
{
&hrp.TConfig{
Parameters: configParameters,
ParametersSetting: &hrp.TParamsConfig{},
},
6, // 3 * 2 * 1
},
{
&hrp.TConfig{
Parameters: configParameters,
},
6, // 3 * 2 * 1
},
// default equals to set overall parameters pick-order to "sequential"
{
&hrp.TConfig{
Parameters: configParameters,
ParametersSetting: &hrp.TParamsConfig{
PickOrder: "sequential",
},
},
6, // 3 * 2 * 1
},
// default equals to set each individual parameters pick-order to "sequential"
{
&hrp.TConfig{
Parameters: configParameters,
ParametersSetting: &hrp.TParamsConfig{
Strategies: map[string]hrp.IteratorStrategy{
"username-password": {Name: "user-info", PickOrder: "sequential"},
"user_agent": {Name: "user-identity", PickOrder: "sequential"},
"app_version": {Name: "app-version", PickOrder: "sequential"},
},
},
},
6, // 3 * 2 * 1
},
{
&hrp.TConfig{
Parameters: configParameters,
ParametersSetting: &hrp.TParamsConfig{
Strategies: map[string]hrp.IteratorStrategy{
"user_agent": {Name: "user-identity", PickOrder: "sequential"},
"app_version": {Name: "app-version", PickOrder: "sequential"},
},
},
},
6, // 3 * 2 * 1
},
// set overall parameters overall pick-order to "random"
// each random parameters only select one item
{
&hrp.TConfig{
Parameters: configParameters,
ParametersSetting: &hrp.TParamsConfig{
PickOrder: "random",
},
},
1, // 1 * 1 * 1
},
// set some individual parameters pick-order to "random"
// this will override overall strategy
{
&hrp.TConfig{
Parameters: configParameters,
ParametersSetting: &hrp.TParamsConfig{
Strategies: map[string]hrp.IteratorStrategy{
"user_agent": {Name: "user-identity", PickOrder: "random"},
},
},
},
3, // 3 * 1 * 1
},
{
&hrp.TConfig{
Parameters: configParameters,
ParametersSetting: &hrp.TParamsConfig{
Strategies: map[string]hrp.IteratorStrategy{
"username-password": {Name: "user-info", PickOrder: "random"},
},
},
},
2, // 1 * 2 * 1
},
// set limit for parameters
{
&hrp.TConfig{
Parameters: configParameters, // total: 6 = 3 * 2 * 1
ParametersSetting: &hrp.TParamsConfig{
Limit: 4, // limit could be less than total
},
},
4,
},
{
&hrp.TConfig{
Parameters: configParameters, // total: 6 = 3 * 2 * 1
ParametersSetting: &hrp.TParamsConfig{
Limit: 9, // limit could also be greater than total
},
},
9,
},
// no parameters
// also will generate one empty item
{
&hrp.TConfig{
Parameters: nil,
ParametersSetting: nil,
},
1,
},
}
parser := hrp.NewParser()
for _, data := range testData {
iterator, err := parser.InitParametersIterator(data.cfg)
if !assert.Nil(t, err) {
t.Fatal()
}
if !assert.Equal(t, data.expectLimit, iterator.Limit) {
t.Fatal()
}
for i := 0; i < data.expectLimit; i++ {
if !assert.True(t, iterator.HasNext()) {
t.Fatal()
}
iterator.Next() // consume next parameters
}
// should not have next
if !assert.False(t, iterator.HasNext()) {
t.Fatal()
}
}
}
func TestInitParametersIteratorUnlimitedCount(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 *hrp.TConfig
}{
// default, no parameters setting
{
&hrp.TConfig{
Parameters: configParameters,
ParametersSetting: &hrp.TParamsConfig{},
},
},
// no parameters
// also will generate one empty item
{
&hrp.TConfig{
Parameters: nil,
ParametersSetting: nil,
},
},
}
parser := hrp.NewParser()
for _, data := range testData {
iterator, err := parser.InitParametersIterator(data.cfg)
if !assert.Nil(t, err) {
t.Fatal()
}
// set unlimited mode
iterator.SetUnlimitedMode()
if !assert.Equal(t, -1, iterator.Limit) {
t.Fatal()
}
for i := 0; i < 100; i++ {
if !assert.True(t, iterator.HasNext()) {
t.Fatal()
}
iterator.Next() // consume next parameters
}
if !assert.Equal(t, 100, iterator.Index) {
t.Fatal()
}
// should also have next
if !assert.True(t, iterator.HasNext()) {
t.Fatal()
}
}
}
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 *hrp.TConfig
checkIndex int
expectParameters map[string]interface{}
}{
// default, no parameters setting
{
&hrp.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
{
&hrp.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: &hrp.TParamsConfig{
Limit: 5, // limit could also be greater than total
Strategies: map[string]hrp.IteratorStrategy{
"username-password": {Name: "user-info", PickOrder: "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
{
&hrp.TConfig{
Parameters: nil,
ParametersSetting: nil,
},
0,
map[string]interface{}{},
},
}
parser := hrp.NewParser()
for _, data := range testData {
iterator, err := parser.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) {
testData := []struct {
multiParameters []hrp.Parameters
expect hrp.Parameters
}{
{
[]hrp.Parameters{
{
{"app_version": 4.0},
},
{
{"username": "test1", "password": "111111"},
{"username": "test2", "password": "222222"},
},
{
{"user_agent": "iOS/10.1"},
{"user_agent": "iOS/10.2"},
},
},
hrp.Parameters{
{"app_version": 4.0, "password": "111111", "user_agent": "iOS/10.1", "username": "test1"},
{"app_version": 4.0, "password": "111111", "user_agent": "iOS/10.2", "username": "test1"},
{"app_version": 4.0, "password": "222222", "user_agent": "iOS/10.1", "username": "test2"},
{"app_version": 4.0, "password": "222222", "user_agent": "iOS/10.2", "username": "test2"},
},
},
{
nil,
nil,
},
{
[]hrp.Parameters{},
nil,
},
}
for _, data := range testData {
parameters := hrp.GenCartesianProduct(data.multiParameters)
if !assert.Equal(t, data.expect, parameters) {
t.Fatal()
}
}
}
func TestConvertParameters(t *testing.T) {
testData := []struct {
key string
parametersRawList interface{}
expect []map[string]interface{}
}{
{
"username-password",
[]map[string]interface{}{
{"username": "test1", "password": 111111, "other": "111"},
{"username": "test2", "password": 222222, "other": "222"},
},
[]map[string]interface{}{
{"username": "test1", "password": 111111},
{"username": "test2", "password": 222222},
},
},
{
"username-password",
[][]string{
{"test1", "111111"},
{"test2", "222222"},
},
[]map[string]interface{}{
{"username": "test1", "password": "111111"},
{"username": "test2", "password": "222222"},
},
},
{
"app_version",
[]float64{3.1, 3.0},
[]map[string]interface{}{
{"app_version": 3.1},
{"app_version": 3.0},
},
},
{
"user_agent",
[]string{"iOS/10.1", "iOS/10.2"},
[]map[string]interface{}{
{"user_agent": "iOS/10.1"},
{"user_agent": "iOS/10.2"},
},
},
}
for _, data := range testData {
value, err := hrp.ConvertParameters(data.key, data.parametersRawList)
if !assert.Nil(t, err) {
t.Fatal()
}
if !assert.Equal(t, data.expect, value) {
t.Fatal()
}
}
}
func TestConvertParametersError(t *testing.T) {
testData := []struct {
key string
parametersRawList interface{}
}{
{
"app_version",
123, // not slice
},
{
"app_version",
"123", // not slice
},
{
"username-password",
[]map[string]interface{}{ // parameter names not match
{"username": "test1", "other": "111"},
{"username": "test2", "other": "222"},
},
},
{
"username-password",
[][]string{ // parameter names length not match
{"test1"},
{"test2"},
},
},
}
for _, data := range testData {
_, err := hrp.ConvertParameters(data.key, data.parametersRawList)
if !assert.Error(t, err) {
t.Fatal()
}
}
}

56
tests/plugin_test.go Normal file
View File

@@ -0,0 +1,56 @@
package tests
import (
"testing"
"github.com/stretchr/testify/assert"
hrp "github.com/httprunner/httprunner/v5"
)
func TestLocateFile(t *testing.T) {
// specify target file path
_, err := hrp.LocateFile(tmpl("plugin/debugtalk.go"), hrp.PluginGoSourceFile)
if !assert.Nil(t, err) {
t.Fatal()
}
// specify path with the same dir
_, err = hrp.LocateFile(tmpl("plugin/debugtalk.py"), hrp.PluginGoSourceFile)
if !assert.Nil(t, err) {
t.Fatal()
}
// specify target file path dir
_, err = hrp.LocateFile(tmpl("plugin/"), hrp.PluginGoSourceFile)
if !assert.Nil(t, err) {
t.Fatal()
}
// specify wrong path
_, err = hrp.LocateFile(".", hrp.PluginGoSourceFile)
if !assert.Error(t, err) {
t.Fatal()
}
_, err = hrp.LocateFile("/abc", hrp.PluginGoSourceFile)
if !assert.Error(t, err) {
t.Fatal()
}
}
func TestLocatePythonPlugin(t *testing.T) {
_, err := hrp.LocatePlugin(tmpl("plugin/debugtalk.py"))
if !assert.Nil(t, err) {
t.Fatal()
}
}
func TestLocateGoPlugin(t *testing.T) {
buildHashicorpGoPlugin()
defer removeHashicorpGoPlugin()
_, err := hrp.LocatePlugin(tmpl("debugtalk.bin"))
if !assert.Nil(t, err) {
t.Fatal()
}
}

302
tests/runner_test.go Normal file
View File

@@ -0,0 +1,302 @@
package tests
import (
"errors"
"fmt"
"os"
"testing"
"time"
"github.com/rs/zerolog/log"
"github.com/stretchr/testify/assert"
hrp "github.com/httprunner/httprunner/v5"
"github.com/httprunner/httprunner/v5/code"
)
func buildHashicorpGoPlugin() {
log.Info().Msg("[init] build hashicorp go plugin")
err := hrp.BuildPlugin(tmpl("plugin/debugtalk.go"), tmpl("debugtalk.bin"))
if err != nil {
log.Error().Err(err).Msg("build hashicorp go plugin failed")
os.Exit(code.GetErrorCode(err))
}
}
func removeHashicorpGoPlugin() {
log.Info().Msg("[teardown] remove hashicorp go plugin")
os.Remove(tmpl("debugtalk.bin"))
}
func buildHashicorpPyPlugin() {
log.Info().Msg("[init] prepare hashicorp python plugin")
src, _ := os.ReadFile(tmpl("plugin/debugtalk.py"))
err := os.WriteFile(tmpl("debugtalk.py"), src, 0o644)
if err != nil {
log.Error().Err(err).Msg("copy hashicorp python plugin failed")
os.Exit(code.GetErrorCode(err))
}
}
func removeHashicorpPyPlugin() {
log.Info().Msg("[teardown] remove hashicorp python plugin")
// on v4.1^, running case will generate .debugtalk_gen.py used by python plugin
os.Remove(tmpl(hrp.PluginPySourceFile))
os.Remove(tmpl(hrp.PluginPySourceGenFile))
}
func TestRunCaseWithGoPlugin(t *testing.T) {
buildHashicorpGoPlugin()
defer removeHashicorpGoPlugin()
assertRunTestCases(t)
}
func TestRunCaseWithPythonPlugin(t *testing.T) {
buildHashicorpPyPlugin()
defer removeHashicorpPyPlugin()
assertRunTestCases(t)
}
func assertRunTestCases(t *testing.T) {
refCase := hrp.TestCasePath(demoTestCaseWithPluginJSONPath)
testcase1 := &hrp.TestCase{
Config: hrp.NewConfig("TestCase1").
SetBaseURL("https://postman-echo.com"),
TestSteps: []hrp.IStep{
hrp.NewStep("testcase1-step1").
GET("/headers").
Validate().
AssertEqual("status_code", 200, "check status code").
AssertEqual("headers.\"Content-Type\"", "application/json; charset=utf-8", "check http response Content-Type"),
hrp.NewStep("testcase1-step2").CallRefCase(
&hrp.TestCase{
Config: hrp.NewConfig("testcase1-step3-ref-case").SetBaseURL("https://postman-echo.com"),
TestSteps: []hrp.IStep{
hrp.NewStep("ip").
GET("/ip").
Validate().
AssertEqual("status_code", 200, "check status code").
AssertEqual("headers.\"Content-Type\"", "application/json; charset=utf-8", "check http response Content-Type"),
},
},
),
hrp.NewStep("testcase1-step3").CallRefCase(&refCase),
},
}
testcase2 := &hrp.TestCase{
Config: hrp.NewConfig("TestCase2").SetWeight(3),
}
r := hrp.NewRunner(t)
r.SetPluginLogOn()
err := r.Run(testcase1, testcase2)
if err != nil {
t.Fatalf("run testcase error: %v", err)
}
}
func TestRunCaseWithThinkTime(t *testing.T) {
buildHashicorpGoPlugin()
defer removeHashicorpGoPlugin()
testcases := []*hrp.TestCase{
{
Config: hrp.NewConfig("TestCase1"),
TestSteps: []hrp.IStep{
hrp.NewStep("thinkTime").SetThinkTime(2),
},
},
{
Config: hrp.NewConfig("TestCase2").
SetThinkTime(hrp.ThinkTimeIgnore, nil, 0),
TestSteps: []hrp.IStep{
hrp.NewStep("thinkTime").SetThinkTime(0.5),
},
},
{
Config: hrp.NewConfig("TestCase3").
SetThinkTime(hrp.ThinkTimeRandomPercentage, nil, 0),
TestSteps: []hrp.IStep{
hrp.NewStep("thinkTime").SetThinkTime(1),
},
},
{
Config: hrp.NewConfig("TestCase4").
SetThinkTime(hrp.ThinkTimeRandomPercentage, map[string]interface{}{"min_percentage": 2, "max_percentage": 3}, 2.5),
TestSteps: []hrp.IStep{
hrp.NewStep("thinkTime").SetThinkTime(1),
},
},
{
Config: hrp.NewConfig("TestCase5"),
TestSteps: []hrp.IStep{
// think time: 3s, random pct: {"min_percentage":1, "max_percentage":1.5}, limit: 4s
hrp.NewStep("thinkTime").CallRefCase(&demoTestCaseWithThinkTimePath),
},
},
}
expectedMinValue := []float64{2, 0, 0.5, 2, 3}
expectedMaxValue := []float64{2.5, 0.5, 2, 3, 10}
for idx, testcase := range testcases {
r := hrp.NewRunner(t)
startTime := time.Now()
err := r.Run(testcase)
if err != nil {
t.Fatalf("run testcase error: %v", err)
}
duration := time.Since(startTime)
minValue := time.Duration(expectedMinValue[idx]*1000) * time.Millisecond
maxValue := time.Duration(expectedMaxValue[idx]*1000) * time.Millisecond
if duration < minValue || duration > maxValue {
t.Fatalf("failed to test think time, expect value: [%v, %v], actual value: %v", minValue, maxValue, duration)
}
}
}
func TestRunCaseWithShell(t *testing.T) {
testcase1 := &hrp.TestCase{
Config: hrp.NewConfig("complex shell with env variables").
WithVariables(map[string]interface{}{
"SS": "12345",
"ABC": "$SS",
}),
TestSteps: []hrp.IStep{
hrp.NewStep("shell21").Shell("echo hello world"),
// NewStep("shell21").Shell("echo $ABC"),
// NewStep("shell21").Shell("which hrp"),
},
}
r := hrp.NewRunner(t)
err := r.Run(testcase1)
if err != nil {
t.Fatal()
}
}
func TestRunCaseWithFunction(t *testing.T) {
fn1 := func() {
fmt.Println("call function1 without return")
}
num := 0
fn2 := func() {
num++
fmt.Println("call function2 with return value")
}
var err3 error
fn3 := func() {
num++
err3 = errors.New("func3 error")
fmt.Println("call function3 with return value and error")
}
testcase1 := &hrp.TestCase{
Config: hrp.NewConfig("call function"),
TestSteps: []hrp.IStep{
hrp.NewStep("fn1").Function(fn1),
hrp.NewStep("fn2").Function(fn2),
hrp.NewStep("fn3").Function(fn3),
},
}
r := hrp.NewRunner(t)
err := r.Run(testcase1)
if err != nil {
t.Fatal()
}
if !assert.Equal(t, num, 2) {
t.Fatal()
}
if !assert.NotNil(t, err3) {
t.Fatal()
}
}
func TestRunCaseWithPluginJSON(t *testing.T) {
buildHashicorpGoPlugin()
defer removeHashicorpGoPlugin()
testCase := hrp.TestCasePath(demoTestCaseWithPluginJSONPath)
err := hrp.NewRunner(nil).Run(&testCase) // hrp.Run(testCase)
if err != nil {
t.Fatal()
}
}
// TODO: FIXME
// func TestRunCaseWithPluginYAML(t *testing.T) {
// buildHashicorpGoPlugin()
// defer removeHashicorpGoPlugin()
// testCase := TestCasePath(demoTestCaseWithPluginYAMLPath)
// err := NewRunner(nil).Run(&testCase) // hrp.Run(testCase)
// if err != nil {
// t.Fatal()
// }
// }
func TestRunCaseWithRefAPI(t *testing.T) {
buildHashicorpGoPlugin()
defer removeHashicorpGoPlugin()
testCase := hrp.TestCasePath(demoTestCaseWithRefAPIPath)
err := hrp.NewRunner(nil).Run(&testCase)
if err != nil {
t.Fatal()
}
refAPI := hrp.APIPath(demoAPIGETPath)
testcase := &hrp.TestCase{
Config: hrp.NewConfig("TestCase").
SetBaseURL("https://postman-echo.com"),
TestSteps: []hrp.IStep{
hrp.NewStep("run referenced api").CallRefAPI(&refAPI),
},
}
r := hrp.NewRunner(t)
err = r.Run(testcase)
if err != nil {
t.Fatal()
}
}
func TestSessionRunner(t *testing.T) {
testcase := hrp.TestCase{
Config: hrp.NewConfig("TestCase").
WithVariables(map[string]interface{}{
"a": 12.3,
"b": 3.45,
"varFoo": "${max($a, $b)}",
}),
TestSteps: []hrp.IStep{
hrp.NewStep("check variables").
WithVariables(map[string]interface{}{
"a": 12.3,
"b": 34.5,
"varFoo": "${max($a, $b)}",
}).
GET("/hello").
Validate().
AssertEqual("status_code", 200, "check status code"),
// AssertEqual("$varFoo", "$b", "check varFoo value"),
},
}
caseRunner, _ := hrp.NewRunner(t).NewCaseRunner(testcase)
sessionRunner := caseRunner.NewSession()
step := testcase.TestSteps[0]
if !assert.Equal(t, step.Config().Variables["varFoo"], "${max($a, $b)}") {
t.Fatal()
}
err := sessionRunner.ParseStep(step)
if err != nil {
t.Fatal()
}
if !assert.Equal(t, step.Config().Variables["varFoo"], 34.5) {
t.Fatal()
}
}

View File

@@ -0,0 +1,73 @@
package tests
import (
"math"
"testing"
hrp "github.com/httprunner/httprunner/v5"
)
func TestRunCaseWithRendezvous(t *testing.T) {
rendezvousBoundaryTestcase := &hrp.TestCase{
Config: hrp.NewConfig("run request with functions").
SetBaseURL("https://postman-echo.com").
WithVariables(map[string]interface{}{
"n": 5,
"a": 12.3,
"b": 3.45,
}),
TestSteps: []hrp.IStep{
hrp.NewStep("test negative number").
SetRendezvous("test negative number").
WithUserNumber(-1),
hrp.NewStep("test overflow number").
SetRendezvous("test overflow number").
WithUserNumber(1000000),
hrp.NewStep("test negative percent").
SetRendezvous("test very low percent").
WithUserPercent(-0.5),
hrp.NewStep("test very low percent").
SetRendezvous("test very low percent").
WithUserPercent(0.00001),
hrp.NewStep("test overflow percent").
SetRendezvous("test overflow percent").
WithUserPercent(1.5),
hrp.NewStep("test conflict params").
SetRendezvous("test conflict params").
WithUserNumber(1).
WithUserPercent(0.123),
hrp.NewStep("test negative timeout").
SetRendezvous("test negative timeout").
WithTimeout(-1000),
},
}
type rendezvousParam struct {
number int64
percent float32
timeout int64
}
expectedRendezvousParams := []rendezvousParam{
{number: 100, percent: 1, timeout: 5000},
{number: 100, percent: 1, timeout: 5000},
{number: 100, percent: 1, timeout: 5000},
{number: 0, percent: 0.00001, timeout: 5000},
{number: 100, percent: 1, timeout: 5000},
{number: 100, percent: 1, timeout: 5000},
{number: 100, percent: 1, timeout: 5000},
}
rendezvousList := hrp.InitRendezvous(rendezvousBoundaryTestcase, 100)
for i, r := range rendezvousList {
if r.Number != expectedRendezvousParams[i].number {
t.Fatalf("run rendezvous %v error: expected number: %v, real number: %v", r.Name, expectedRendezvousParams[i].number, r.Number)
}
if math.Abs(float64(r.Percent-expectedRendezvousParams[i].percent)) > 0.001 {
t.Fatalf("run rendezvous %v error: expected percent: %v, real percent: %v", r.Name, expectedRendezvousParams[i].percent, r.Percent)
}
if r.Timeout != expectedRendezvousParams[i].timeout {
t.Fatalf("run rendezvous %v error: expected timeout: %v, real timeout: %v", r.Name, expectedRendezvousParams[i].timeout, r.Timeout)
}
}
}

215
tests/step_request_test.go Normal file
View File

@@ -0,0 +1,215 @@
package tests
import (
"testing"
"time"
hrp "github.com/httprunner/httprunner/v5"
"github.com/stretchr/testify/assert"
)
var (
stepGET = hrp.NewStep("get with params").
GET("/get").
WithParams(map[string]interface{}{"foo1": "bar1", "foo2": "bar2"}).
WithHeaders(map[string]string{"User-Agent": "HttpRunnerPlus"}).
WithCookies(map[string]string{"user": "debugtalk"}).
Validate().
AssertEqual("status_code", 200, "check status code").
AssertEqual("headers.\"Content-Type\"", "application/json; charset=utf-8", "check header Content-Type").
AssertEqual("body.args.foo1", "bar1", "check param foo1").
AssertEqual("body.args.foo2", "bar2", "check param foo2")
stepPOSTData = hrp.NewStep("post form data").
POST("/post").
WithParams(map[string]interface{}{"foo1": "bar1", "foo2": "bar2"}).
WithHeaders(map[string]string{"User-Agent": "HttpRunnerPlus", "Content-Type": "application/x-www-form-urlencoded"}).
WithBody("a=1&b=2").
WithCookies(map[string]string{"user": "debugtalk"}).
Validate().
AssertEqual("status_code", 200, "check status code")
)
func TestRunRequestGetToStruct(t *testing.T) {
tStep := stepGET
if tStep.Request.Method != hrp.HTTP_GET {
t.Fatalf("tStep.Request.Method != GET")
}
if tStep.Request.URL != "/get" {
t.Fatalf("tStep.Request.URL != '/get'")
}
if tStep.Request.Params["foo1"] != "bar1" || tStep.Request.Params["foo2"] != "bar2" {
t.Fatalf("tStep.Request.Params mismatch")
}
if tStep.Request.Headers["User-Agent"] != "HttpRunnerPlus" {
t.Fatalf("tStep.Request.Headers mismatch")
}
if tStep.Request.Cookies["user"] != "debugtalk" {
t.Fatalf("tStep.Request.Cookies mismatch")
}
validator, ok := tStep.Validators[0].(hrp.Validator)
if !ok || validator.Check != "status_code" || validator.Expect != 200 {
t.Fatalf("tStep.Validators mismatch")
}
}
func TestRunRequestPostDataToStruct(t *testing.T) {
tStep := stepPOSTData
if tStep.Request.Method != hrp.HTTP_POST {
t.Fatalf("tStep.Request.Method != POST")
}
if tStep.Request.URL != "/post" {
t.Fatalf("tStep.Request.URL != '/post'")
}
if tStep.Request.Params["foo1"] != "bar1" || tStep.Request.Params["foo2"] != "bar2" {
t.Fatalf("tStep.Request.Params mismatch")
}
if tStep.Request.Headers["User-Agent"] != "HttpRunnerPlus" {
t.Fatalf("tStep.Request.Headers mismatch")
}
if tStep.Request.Cookies["user"] != "debugtalk" {
t.Fatalf("tStep.Request.Cookies mismatch")
}
if tStep.Request.Body != "a=1&b=2" {
t.Fatalf("tStep.Request.Data mismatch")
}
validator, ok := tStep.Validators[0].(hrp.Validator)
if !ok || validator.Check != "status_code" || validator.Expect != 200 {
t.Fatalf("tStep.Validators mismatch")
}
}
func TestRunRequestStatOn(t *testing.T) {
testcase := hrp.TestCase{
Config: hrp.NewConfig("test").SetBaseURL("https://postman-echo.com"),
TestSteps: []hrp.IStep{stepGET, stepPOSTData},
}
caseRunner, _ := hrp.NewRunner(t).SetHTTPStatOn().NewCaseRunner(testcase)
sessionRunner := caseRunner.NewSession()
summary, err := sessionRunner.Start(nil)
if err != nil {
t.Fatal()
}
stat := summary.Records[0].HttpStat
if !assert.GreaterOrEqual(t, stat["DNSLookup"], int64(0)) {
t.Fatal()
}
if !assert.Greater(t, stat["TCPConnection"], int64(0)) {
t.Fatal()
}
if !assert.Greater(t, stat["TLSHandshake"], int64(0)) {
t.Fatal()
}
if !assert.Greater(t, stat["ServerProcessing"], int64(0)) {
t.Fatal()
}
if !assert.GreaterOrEqual(t, stat["ContentTransfer"], int64(0)) {
t.Fatal()
}
if !assert.GreaterOrEqual(t, stat["NameLookup"], int64(0)) {
t.Fatal()
}
if !assert.Greater(t, stat["Connect"], int64(0)) {
t.Fatal()
}
if !assert.Greater(t, stat["Pretransfer"], int64(0)) {
t.Fatal()
}
if !assert.Greater(t, stat["StartTransfer"], int64(0)) {
t.Fatal()
}
if !assert.Greater(t, stat["Total"], int64(5)) {
t.Fatal()
}
if !assert.Less(t, stat["Total"]-summary.Records[0].Elapsed, int64(3)) {
t.Fatal()
}
// reuse connection
stat = summary.Records[1].HttpStat
if !assert.Equal(t, int64(0), stat["DNSLookup"]) {
t.Fatal()
}
if !assert.Equal(t, int64(0), stat["TCPConnection"]) {
t.Fatal()
}
if !assert.Equal(t, int64(0), stat["TLSHandshake"]) {
t.Fatal()
}
if !assert.Greater(t, stat["ServerProcessing"], int64(1)) {
t.Fatal()
}
if !assert.Equal(t, int64(0), stat["NameLookup"]) {
t.Fatal()
}
if !assert.Equal(t, int64(0), stat["Connect"]) {
t.Fatal()
}
if !assert.Equal(t, int64(0), stat["Pretransfer"]) {
t.Fatal()
}
if !assert.Greater(t, stat["StartTransfer"], int64(0)) {
t.Fatal()
}
if !assert.Greater(t, stat["Total"], int64(1)) {
t.Fatal()
}
if !assert.Less(t, stat["Total"]-summary.Records[0].Elapsed, int64(100)) {
t.Fatal()
}
}
func TestRunCaseWithTimeout(t *testing.T) {
r := hrp.NewRunner(t)
// global timeout
testcase1 := &hrp.TestCase{
Config: hrp.NewConfig("TestCase1").
SetRequestTimeout(10). // set global timeout to 10s
SetBaseURL("https://postman-echo.com"),
TestSteps: []hrp.IStep{
hrp.NewStep("step1").
GET("/delay/1").
Validate().
AssertEqual("status_code", 200, "check status code"),
},
}
err := r.Run(testcase1)
if !assert.NoError(t, err) { // assert no error
t.FailNow()
}
testcase2 := &hrp.TestCase{
Config: hrp.NewConfig("TestCase2").
SetRequestTimeout(5). // set global timeout to 10s
SetBaseURL("https://postman-echo.com"),
TestSteps: []hrp.IStep{
hrp.NewStep("step1").
GET("/delay/10").
Validate().
AssertEqual("status_code", 200, "check status code"),
},
}
err = r.Run(testcase2)
if !assert.Error(t, err) { // assert error
t.FailNow()
}
// step timeout
testcase3 := &hrp.TestCase{
Config: hrp.NewConfig("TestCase3").
SetRequestTimeout(10).
SetBaseURL("https://postman-echo.com"),
TestSteps: []hrp.IStep{
hrp.NewStep("step2").
GET("/delay/11").
SetTimeout(15*time.Second). // set step timeout to 4s
Validate().
AssertEqual("status_code", 200, "check status code"),
},
}
err = r.Run(testcase3)
if !assert.NoError(t, err) {
t.FailNow()
}
}

89
tests/step_ui_test.go Normal file
View File

@@ -0,0 +1,89 @@
//go:build localtest
package tests
import (
"testing"
hrp "github.com/httprunner/httprunner/v5"
"github.com/httprunner/httprunner/v5/uixt/option"
)
func TestIOSSettingsAction(t *testing.T) {
testCase := &hrp.TestCase{
Config: hrp.NewConfig("ios ui action on Settings").
SetIOS(option.WithWDAPort(8700), option.WithWDAMjpegPort(8800)),
TestSteps: []hrp.IStep{
hrp.NewStep("launch Settings").
IOS().Home().TapByOCR("设置").
Validate().
AssertNameExists("飞行模式").
AssertLabelExists("蓝牙").
AssertOCRExists("个人热点"),
hrp.NewStep("swipe up and down").
IOS().SwipeUp().SwipeUp().SwipeDown(),
},
}
err := hrp.NewRunner(t).Run(testCase)
if err != nil {
t.Fatal(err)
}
}
func TestIOSSearchApp(t *testing.T) {
testCase := &hrp.TestCase{
Config: hrp.NewConfig("ios ui action on Search App 资源库"),
TestSteps: []hrp.IStep{
hrp.NewStep("进入 App 资源库 搜索框").
IOS().Home().SwipeLeft().SwipeLeft().TapByCV("dewey-search-field").
Validate().
AssertLabelExists("取消"),
hrp.NewStep("搜索抖音").
IOS().Input("抖音\n"),
},
}
err := hrp.NewRunner(t).Run(testCase)
if err != nil {
t.Fatal(err)
}
}
func TestIOSAppLaunch(t *testing.T) {
testCase := &hrp.TestCase{
Config: hrp.NewConfig("启动 & 关闭 App").
SetIOS(option.WithWDAPort(8700), option.WithWDAMjpegPort(8800)),
TestSteps: []hrp.IStep{
hrp.NewStep("终止今日头条").
IOS().AppTerminate("com.ss.iphone.article.News"),
hrp.NewStep("启动今日头条").
IOS().AppLaunch("com.ss.iphone.article.News"),
hrp.NewStep("终止今日头条").
IOS().AppTerminate("com.ss.iphone.article.News"),
hrp.NewStep("启动今日头条").
IOS().AppLaunch("com.ss.iphone.article.News"),
},
}
err := hrp.NewRunner(t).Run(testCase)
if err != nil {
t.Fatal(err)
}
}
func TestAndroidAction(t *testing.T) {
testCase := &hrp.TestCase{
Config: hrp.NewConfig("android ui action"),
TestSteps: []hrp.IStep{
hrp.NewStep("launch douyin").
Android().Serial("xxx").TapByOCR("抖音").
Validate().
AssertNameExists("首页", "首页 tab 不存在").
AssertNameExists("消息", "消息 tab 不存在"),
hrp.NewStep("swipe up and down").
Android().Serial("xxx").SwipeUp().SwipeUp().SwipeDown(),
},
}
err := hrp.NewRunner(t).Run(testCase)
if err != nil {
t.Fatal(err)
}
}

67
tests/summary_test.go Normal file
View File

@@ -0,0 +1,67 @@
package tests
import (
"testing"
"github.com/stretchr/testify/assert"
hrp "github.com/httprunner/httprunner/v5"
)
func TestGenHTMLReport(t *testing.T) {
summary := hrp.NewSummary()
caseSummary1 := hrp.NewCaseSummary()
stepResult1 := &hrp.StepResult{}
caseSummary1.AddStepResult(stepResult1)
summary.AddCaseSummary(caseSummary1)
caseSummary2 := hrp.NewCaseSummary()
stepResult2 := &hrp.StepResult{
Name: "Test",
StepType: hrp.StepTypeRequest,
Success: false,
ContentSize: 0,
Attachments: "err",
}
caseSummary2.AddStepResult(stepResult2)
summary.AddCaseSummary(caseSummary2)
_, err := summary.GenSummary()
if err != nil {
t.Error(err)
}
err = summary.GenHTMLReport()
if err != nil {
t.Error(err)
}
}
func TestTestCaseSummary_AddStepResult(t *testing.T) {
caseSummary := hrp.NewCaseSummary()
stepResult1 := &hrp.StepResult{
Name: "Test1",
StepType: hrp.StepTypeRequest,
Success: true,
ContentSize: 0,
Attachments: "err",
}
caseSummary.AddStepResult(stepResult1)
stepResult2 := &hrp.StepResult{
Name: "Test2",
StepType: hrp.StepTypeTestCase,
Success: false,
ContentSize: 0,
Attachments: "err",
Data: []*hrp.StepResult{stepResult1},
}
caseSummary.AddStepResult(stepResult2)
if !assert.Equal(t, 2, len(caseSummary.Records)) {
t.Fatal()
}
if !assert.False(t, caseSummary.Success) {
t.Fatal()
}
}

174
tests/testcase_test.go Normal file
View File

@@ -0,0 +1,174 @@
package tests
import (
"path/filepath"
"testing"
hrp "github.com/httprunner/httprunner/v5"
)
const (
hrpExamplesDir = "../examples/hrp"
)
// tmpl returns template file path
func tmpl(relativePath string) string {
return filepath.Join("internal/scaffold/templates/", relativePath)
}
var (
demoTestCaseWithPluginJSONPath = tmpl("testcases/demo_with_funplugin.json")
demoTestCaseWithPluginYAMLPath = tmpl("testcases/demo_with_funplugin.yaml")
demoTestCaseWithoutPluginJSONPath = tmpl("testcases/demo_without_funplugin.json")
demoTestCaseWithoutPluginYAMLPath = tmpl("testcases/demo_without_funplugin.yaml")
demoTestCaseWithRefAPIPath = tmpl("testcases/demo_ref_api.json")
demoAPIGETPath = tmpl("/api/get.yml")
)
var demoTestCaseWithThinkTimePath hrp.TestCasePath = hrpExamplesDir + "/think_time_test.json"
var demoTestCaseWithPlugin = &hrp.TestCase{
Config: hrp.NewConfig("demo with complex mechanisms").
SetBaseURL("https://postman-echo.com").
WithVariables(map[string]interface{}{ // global level variables
"n": "${sum_ints(1, 2, 2)}",
"a": "${sum(10, 2.3)}",
"b": 3.45,
"varFoo1": "${gen_random_string($n)}",
"varFoo2": "${max($a, $b)}", // 12.3; eval with built-in function
}),
TestSteps: []hrp.IStep{
hrp.NewStep("transaction 1 start").StartTransaction("tran1"), // start transaction
hrp.NewStep("get with params").
WithVariables(map[string]interface{}{ // step level variables
"n": 3, // inherit config level variables if not set in step level, a/varFoo1
"b": 34.5, // override config level variable if existed, n/b/varFoo2
"varFoo2": "${max($a, $b)}", // 34.5; override variable b and eval again
"name": "get with params",
}).
SetupHook("${setup_hook_example($name)}").
GET("/get").
TeardownHook("${teardown_hook_example($name)}").
WithParams(map[string]interface{}{"foo1": "$varFoo1", "foo2": "$varFoo2"}). // request with params
WithHeaders(map[string]string{"User-Agent": "HttpRunnerPlus"}). // request with headers
Extract().
WithJmesPath("body.args.foo1", "varFoo1"). // extract variable with jmespath
Validate().
AssertEqual("status_code", 200, "check response status code"). // validate response status code
AssertStartsWith("headers.\"Content-Type\"", "application/json", ""). // validate response header
AssertLengthEqual("body.args.foo1", 5, "check args foo1"). // validate response body with jmespath
AssertLengthEqual("$varFoo1", 5, "check args foo1"). // assert with extracted variable from current step
AssertEqual("body.args.foo2", "34.5", "check args foo2"), // notice: request params value will be converted to string
hrp.NewStep("transaction 1 end").EndTransaction("tran1"), // end transaction
hrp.NewStep("post json data").
POST("/post").
WithBody(map[string]interface{}{
"foo1": "$varFoo1", // reference former extracted variable
"foo2": "${max($a, $b)}", // 12.3; step level variables are independent, variable b is 3.45 here
}).
Validate().
AssertEqual("status_code", 200, "check status code").
AssertLengthEqual("body.json.foo1", 5, "check args foo1").
AssertEqual("body.json.foo2", 12.3, "check args foo2"),
hrp.NewStep("post form data").
POST("/post").
WithHeaders(map[string]string{"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}).
WithBody(map[string]interface{}{
"foo1": "$varFoo1", // reference former extracted variable
"foo2": "${max($a, $b)}", // 12.3; step level variables are independent, variable b is 3.45 here
"time": "${get_timestamp()}",
}).
Extract().
WithJmesPath("body.form.time", "varTime").
Validate().
AssertEqual("status_code", 200, "check status code").
AssertLengthEqual("body.form.foo1", 5, "check args foo1").
AssertEqual("body.form.foo2", "12.3", "check args foo2"), // form data will be converted to string
hrp.NewStep("get with timestamp").
GET("/get").WithParams(map[string]interface{}{"time": "$varTime"}).
Validate().
AssertLengthEqual("body.args.time", 13, "check extracted var timestamp"),
},
}
var demoTestCaseWithoutPlugin = &hrp.TestCase{
Config: hrp.NewConfig("demo without custom function plugin").
SetBaseURL("https://postman-echo.com").
WithVariables(map[string]interface{}{ // global level variables
"n": 5,
"a": 12.3,
"b": 3.45,
"varFoo1": "${gen_random_string($n)}",
"varFoo2": "${max($a, $b)}", // 12.3; eval with built-in function
}),
TestSteps: []hrp.IStep{
hrp.NewStep("transaction 1 start").StartTransaction("tran1"), // start transaction
hrp.NewStep("get with params").
WithVariables(map[string]interface{}{ // step level variables
"n": 3, // inherit config level variables if not set in step level, a/varFoo1
"b": 34.5, // override config level variable if existed, n/b/varFoo2
"varFoo2": "${max($a, $b)}", // 34.5; override variable b and eval again
"name": "get with params",
}).
GET("/get").
WithParams(map[string]interface{}{"foo1": "$varFoo1", "foo2": "$varFoo2"}). // request with params
WithHeaders(map[string]string{"User-Agent": "HttpRunnerPlus"}). // request with headers
Extract().
WithJmesPath("body.args.foo1", "varFoo1"). // extract variable with jmespath
Validate().
AssertEqual("status_code", 200, "check response status code"). // validate response status code
AssertStartsWith("headers.\"Content-Type\"", "application/json", ""). // validate response header
AssertLengthEqual("body.args.foo1", 5, "check args foo1"). // validate response body with jmespath
AssertLengthEqual("$varFoo1", 5, "check args foo1"). // assert with extracted variable from current step
AssertEqual("body.args.foo2", "34.5", "check args foo2"), // notice: request params value will be converted to string
hrp.NewStep("transaction 1 end").EndTransaction("tran1"), // end transaction
hrp.NewStep("post json data").
POST("/post").
WithBody(map[string]interface{}{
"foo1": "$varFoo1", // reference former extracted variable
"foo2": "${max($a, $b)}", // 12.3; step level variables are independent, variable b is 3.45 here
}).
Validate().
AssertEqual("status_code", 200, "check status code").
AssertLengthEqual("body.json.foo1", 5, "check args foo1").
AssertEqual("body.json.foo2", 12.3, "check args foo2"),
hrp.NewStep("post form data").
POST("/post").
WithHeaders(map[string]string{"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}).
WithBody(map[string]interface{}{
"foo1": "$varFoo1", // reference former extracted variable
"foo2": "${max($a, $b)}", // 12.3; step level variables are independent, variable b is 3.45 here
"time": "${get_timestamp()}",
}).
Extract().
WithJmesPath("body.form.time", "varTime").
Validate().
AssertEqual("status_code", 200, "check status code").
AssertLengthEqual("body.form.foo1", 5, "check args foo1").
AssertEqual("body.form.foo2", "12.3", "check args foo2"), // form data will be converted to string
hrp.NewStep("get with timestamp").
GET("/get").WithParams(map[string]interface{}{"time": "$varTime"}).
Validate().
AssertLengthEqual("body.args.time", 13, "check extracted var timestamp"),
},
}
func TestGenDemoTestCase(t *testing.T) {
err := demoTestCaseWithPlugin.Dump2JSON(demoTestCaseWithPluginJSONPath)
if err != nil {
t.Fatal()
}
err = demoTestCaseWithPlugin.Dump2YAML(demoTestCaseWithPluginYAMLPath)
if err != nil {
t.Fatal()
}
err = demoTestCaseWithoutPlugin.Dump2JSON(demoTestCaseWithoutPluginJSONPath)
if err != nil {
t.Fatal()
}
err = demoTestCaseWithoutPlugin.Dump2YAML(demoTestCaseWithoutPluginYAMLPath)
if err != nil {
t.Fatal()
}
}