mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-06 20:32:44 +08:00
refactor: move tests
This commit is contained in:
45
tests/build_test.go
Normal file
45
tests/build_test.go
Normal 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
96
tests/loader_test.go
Normal 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
540
tests/parameters_test.go
Normal 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
56
tests/plugin_test.go
Normal 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
302
tests/runner_test.go
Normal 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()
|
||||
}
|
||||
}
|
||||
73
tests/step_rendezvous_test.go
Normal file
73
tests/step_rendezvous_test.go
Normal 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
215
tests/step_request_test.go
Normal 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
89
tests/step_ui_test.go
Normal 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
67
tests/summary_test.go
Normal 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
174
tests/testcase_test.go
Normal 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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user