feat: support run testcases in specified folder path #1198

This commit is contained in:
debugtalk
2022-03-28 18:12:51 +08:00
parent e31f23cbe0
commit f84bf3b1a6
7 changed files with 121 additions and 17 deletions

View File

@@ -26,7 +26,7 @@ jobs:
- name: Run start project
run: ./output/hrp startproject demo
- name: Run generated demo tests
run: ./output/hrp run demo/testcases/demo_with_funplugin.json demo/testcases/demo_requests.yml demo/testcases/demo_ref_testcase.yml
run: ./output/hrp run demo/testcases/
- name: Run demo in examples
run: |
./output/hrp run examples/demo-with-py-plugin/testcases/demo_with_funplugin.json
@@ -51,7 +51,7 @@ jobs:
- name: Run start project
run: ./output/hrp startproject demo --go
- name: Run generated demo tests
run: ./output/hrp run demo/testcases/demo_with_funplugin.json demo/testcases/demo_requests.yml demo/testcases/demo_ref_testcase.yml
run: ./output/hrp run demo/testcases/
- name: Run demo in examples
run: |
go build -o examples/demo-with-go-plugin/debugtalk.bin examples/demo-with-go-plugin/plugin/debugtalk.go

View File

@@ -7,6 +7,7 @@
**go version**
- feat: add `--profile` flag for har2case to support overwrite headers/cookies with specified yaml/json profile file
- feat: support run testcases in specified folder path
- change: integrate [sentry sdk][sentry sdk] for panic reporting and analysis
- change: lock funplugin version when creating scaffold project
- fix: call referenced api/testcase with relative path
@@ -30,8 +31,8 @@
## hrp-v0.7.0 (2022-03-15)
- feat: support API layer for testcase #94
- feat: support global headers for testcase #95
- feat: support API layer for testcase
- feat: support global headers for testcase
- feat: support call referenced testcase by path in YAML/JSON testcases
- fix: decode failure when content-encoding is deflate
- fix: unstable RPS when load testing in high concurrency

View File

@@ -38,11 +38,14 @@ func (b *HRPBoomer) Run(testcases ...ITestCase) {
defer sdk.SendEvent(event.StartTiming("execution"))
var taskSlice []*boomer.Task
for _, iTestCase := range testcases {
testcase, err := iTestCase.ToTestCase()
if err != nil {
panic(err)
}
// load all testcases
testCases, err := loadTestCases(testcases...)
if err != nil {
panic(err)
}
for _, testcase := range testCases {
cfg := testcase.Config
err = initParameterIterator(cfg, "boomer")
if err != nil {

View File

@@ -116,7 +116,7 @@ func (tc *TCase) ToTestCase() (*TestCase, error) {
var apiFullPath string
if apiPath, ok := step.API.(string); ok {
apiFullPath = filepath.Join(projectRootDir, apiPath)
} else if apiPath, ok := step.API.(APIPath); ok {
} else if apiPath, ok := step.API.(*APIPath); ok {
apiFullPath = filepath.Join(projectRootDir, apiPath.GetPath())
} else {
return nil, errors.New("invalid api format")

View File

@@ -132,6 +132,18 @@ func IsFilePathExists(path string) bool {
return true
}
// IsFolderPathExists returns true if path exists and path is folder
func IsFolderPathExists(path string) bool {
info, err := os.Stat(path)
if err != nil {
// path not exists
return false
}
// path exists and is dir
return info.IsDir()
}
func EnsureFolderExists(folderPath string) error {
if !IsPathExists(folderPath) {
err := CreateFolder(folderPath)

View File

@@ -10,6 +10,7 @@ import (
"fmt"
"html/template"
"io"
"io/ioutil"
"net"
"net/http"
"net/http/httputil"
@@ -148,15 +149,17 @@ func (r *HRPRunner) Run(testcases ...ITestCase) error {
defer sdk.SendEvent(event.StartTiming("execution"))
// record execution data to summary
s := newOutSummary()
for _, iTestCase := range testcases {
testcase, err := iTestCase.ToTestCase()
if err != nil {
log.Error().Err(err).Msg("[Run] convert ITestCase interface to TestCase struct failed")
return err
}
// load all testcases
testCases, err := loadTestCases(testcases...)
if err != nil {
return err
}
for _, testcase := range testCases {
cfg := testcase.Config
// parse config parameters
err = initParameterIterator(cfg, "runner")
err := initParameterIterator(cfg, "runner")
if err != nil {
log.Error().Interface("parameters", cfg.Parameters).Err(err).Msg("parse config parameters failed")
return err
@@ -201,6 +204,56 @@ func (r *HRPRunner) Run(testcases ...ITestCase) error {
return nil
}
func loadTestCases(iTestCases ...ITestCase) ([]*TestCase, error) {
testCases := make([]*TestCase, 0)
for _, iTestCase := range iTestCases {
if _, ok := iTestCase.(*TestCase); ok {
testcase, err := iTestCase.ToTestCase()
if err != nil {
log.Error().Err(err).Msg("failed to convert ITestCase interface to TestCase struct")
return nil, err
}
testCases = append(testCases, testcase)
continue
}
// iTestCase should be a TestCasePath, file path or folder path
testCasePath, ok := iTestCase.(*TestCasePath)
if !ok {
return nil, errors.New("invalid iTestCase type")
}
casePaths := make([]*TestCasePath, 0)
casePath := iTestCase.GetPath()
if builtin.IsFolderPathExists(casePath) {
// folder path
files, err := ioutil.ReadDir(casePath)
if err != nil {
return nil, errors.Wrap(err, "failed to read dir")
}
for _, f := range files {
path := TestCasePath(filepath.Join(casePath, f.Name()))
casePaths = append(casePaths, &path)
}
} else {
// file path
casePaths = append(casePaths, testCasePath)
}
for _, path := range casePaths {
tc, err := path.ToTestCase()
if err != nil {
continue
}
testCases = append(testCases, tc)
}
}
log.Info().Int("count", len(testCases)).Msg("load testcases successfully")
return testCases, nil
}
func (r *HRPRunner) newCaseRunner(testcase *TestCase) *caseRunner {
caseRunner := &caseRunner{
TestCase: testcase,

View File

@@ -8,6 +8,7 @@ import (
"time"
"github.com/rs/zerolog/log"
"github.com/stretchr/testify/assert"
"github.com/httprunner/httprunner/hrp/internal/scaffold"
)
@@ -283,3 +284,37 @@ func TestRunCaseWithRefAPI(t *testing.T) {
t.Fail()
}
}
func TestLoadTestCases(t *testing.T) {
// load test cases from folder path
tc := TestCasePath(templatesDir + "testcases")
testCases, err := loadTestCases(&tc)
if !assert.Nil(t, err) {
t.Fail()
}
if !assert.GreaterOrEqual(t, len(testCases), 5) {
t.Fail()
}
// load test cases from single file path
tc = demoTestCaseWithPluginJSONPath
testCases, err = loadTestCases(&tc)
if !assert.Nil(t, err) {
t.Fail()
}
if !assert.Equal(t, len(testCases), 1) {
t.Fail()
}
// load test cases from TestCase instance
testcase := &TestCase{
Config: NewConfig("TestCase").SetWeight(3),
}
testCases, err = loadTestCases(testcase)
if !assert.Nil(t, err) {
t.Fail()
}
if !assert.Equal(t, len(testCases), 1) {
t.Fail()
}
}