mirror of
https://github.com/httprunner/httprunner.git
synced 2026-06-03 23:09:36 +08:00
change: add unittest for override
This commit is contained in:
@@ -30,14 +30,18 @@ Global Flags:
|
||||
1. `--to-json / --to-yaml / --to-gotest / --to-pytest` 用于将输入转化为对应形态的测试用例,四个选项中最多只能指定一个,如果不指定则默认会将输入转化为 JSON 形态的测试用例
|
||||
2. `--output-dir` 后接测试用例的期望输出目录的路径,用于将转换生成的测试用例输出到对应的文件夹
|
||||
3. `--profile` 后接 profile 配置文件的路径,目前支持替换(不存在则会创建)或者覆盖输入的外部脚本/测试用例中的 `Headers` 和 `Cookies` 信息,profile 文件的后缀可以为 `json/yaml/yml`,下面给出两类 profile 配置文件的示例:
|
||||
|
||||
- 根据 profile 替换指定的 `Headers` 和 `Cookies` 信息
|
||||
|
||||
```yaml
|
||||
headers:
|
||||
Header1: "this header will be created or updated"
|
||||
cookies:
|
||||
Cookie1: "this cookie will be created or updated"
|
||||
```
|
||||
|
||||
- 根据 profile 覆盖原有的 `Headers` 和 `Cookies` 信息
|
||||
|
||||
```yaml
|
||||
override: true
|
||||
headers:
|
||||
|
||||
@@ -21,43 +21,6 @@ const (
|
||||
suffixPyTest = ".py"
|
||||
)
|
||||
|
||||
type InputType int
|
||||
|
||||
const (
|
||||
InputTypeUnknown InputType = iota // default input type: unknown
|
||||
InputTypeHAR
|
||||
InputTypePostman
|
||||
InputTypeSwagger
|
||||
InputTypeJMeter
|
||||
InputTypeJSON
|
||||
InputTypeYAML
|
||||
InputTypeGoTest
|
||||
InputTypePyTest
|
||||
)
|
||||
|
||||
func (inputType InputType) String() string {
|
||||
switch inputType {
|
||||
case InputTypeHAR:
|
||||
return "har"
|
||||
case InputTypePostman:
|
||||
return "postman"
|
||||
case InputTypeSwagger:
|
||||
return "swagger"
|
||||
case InputTypeJMeter:
|
||||
return "jmeter"
|
||||
case InputTypeJSON:
|
||||
return "json testcase"
|
||||
case InputTypeYAML:
|
||||
return "yaml testcase"
|
||||
case InputTypeGoTest:
|
||||
return "gotest script"
|
||||
case InputTypePyTest:
|
||||
return "pytest script"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
type OutputType int
|
||||
|
||||
const (
|
||||
@@ -80,15 +43,6 @@ func (outputType OutputType) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
// TCaseConverter holds the common properties of case converter
|
||||
type TCaseConverter struct {
|
||||
InputPath string
|
||||
OutputDir string
|
||||
InputType InputType
|
||||
OutputType OutputType
|
||||
TCase *hrp.TCase
|
||||
}
|
||||
|
||||
// Profile is used to override or update(create if not existed) original headers and cookies
|
||||
type Profile struct {
|
||||
Override bool `json:"override" yaml:"override"`
|
||||
@@ -96,6 +50,57 @@ type Profile struct {
|
||||
Cookies map[string]string `json:"cookies" yaml:"cookies"`
|
||||
}
|
||||
|
||||
func Run(outputType OutputType, outputDir, profilePath string, args []string) {
|
||||
// report event
|
||||
sdk.SendEvent(sdk.EventTracking{
|
||||
Category: "ConvertTests",
|
||||
Action: fmt.Sprintf("hrp convert --to-%s", outputType.String()),
|
||||
})
|
||||
|
||||
var outputFiles []string
|
||||
for _, path := range args {
|
||||
// loads source file and convert to TCase format
|
||||
tCase, err := LoadTCase(path)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Str("path", path).Msg("construct case loader failed")
|
||||
continue
|
||||
}
|
||||
|
||||
caseConverter := &TCaseConverter{
|
||||
SourcePath: path,
|
||||
OutputDir: outputDir,
|
||||
OutputType: outputType,
|
||||
TCase: tCase,
|
||||
}
|
||||
|
||||
// override TCase with profile
|
||||
if profilePath != "" {
|
||||
caseConverter.overrideWithProfile(profilePath)
|
||||
}
|
||||
|
||||
// convert TCase format to target case format
|
||||
var outputFile string
|
||||
switch outputType {
|
||||
case OutputTypeYAML:
|
||||
outputFile, err = caseConverter.ToYAML()
|
||||
case OutputTypeGoTest:
|
||||
outputFile, err = caseConverter.ToGoTest()
|
||||
case OutputTypePyTest:
|
||||
outputFile, err = caseConverter.ToPyTest()
|
||||
default:
|
||||
outputFile, err = caseConverter.ToJSON()
|
||||
}
|
||||
if err != nil {
|
||||
log.Error().Err(err).
|
||||
Str("source path", path).
|
||||
Msg("convert case failed")
|
||||
continue
|
||||
}
|
||||
outputFiles = append(outputFiles, outputFile)
|
||||
}
|
||||
log.Info().Strs("output files", outputFiles).Msg("conversion completed")
|
||||
}
|
||||
|
||||
// LoadTCase loads source file and convert to TCase type
|
||||
func LoadTCase(path string) (*hrp.TCase, error) {
|
||||
extName := filepath.Ext(path)
|
||||
@@ -156,19 +161,27 @@ func LoadTCase(path string) (*hrp.TCase, error) {
|
||||
return nil, fmt.Errorf("unsupported file type: %v", extName)
|
||||
}
|
||||
|
||||
// TCaseConverter holds the common properties of case converter
|
||||
type TCaseConverter struct {
|
||||
SourcePath string
|
||||
OutputDir string
|
||||
OutputType OutputType
|
||||
TCase *hrp.TCase
|
||||
}
|
||||
|
||||
func (c *TCaseConverter) genOutputPath(suffix string) string {
|
||||
outFileFullName := builtin.GetOutputNameWithoutExtension(c.InputPath) + suffix
|
||||
outFileFullName := builtin.GetOutputNameWithoutExtension(c.SourcePath) + suffix
|
||||
if c.OutputDir != "" {
|
||||
return filepath.Join(c.OutputDir, outFileFullName)
|
||||
} else {
|
||||
return filepath.Join(filepath.Dir(c.InputPath), outFileFullName)
|
||||
return filepath.Join(filepath.Dir(c.SourcePath), outFileFullName)
|
||||
}
|
||||
// TODO avoid outFileFullName conflict?
|
||||
}
|
||||
|
||||
// convert TCase to pytest case
|
||||
func (c *TCaseConverter) ToPyTest() (string, error) {
|
||||
args := append([]string{"make"}, c.InputPath)
|
||||
args := append([]string{"make"}, c.SourcePath)
|
||||
err := builtin.ExecPython3Command("httprunner", args...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -201,54 +214,6 @@ func (c *TCaseConverter) ToYAML() (string, error) {
|
||||
return yamlPath, nil
|
||||
}
|
||||
|
||||
func Run(outputType OutputType, outputDir, profilePath string, args []string) {
|
||||
// report event
|
||||
sdk.SendEvent(sdk.EventTracking{
|
||||
Category: "ConvertTests",
|
||||
Action: fmt.Sprintf("hrp convert --to-%s", outputType.String()),
|
||||
})
|
||||
|
||||
var outputFiles []string
|
||||
for _, path := range args {
|
||||
// loads source file in support types and convert to TCase format
|
||||
tCase, err := LoadTCase(path)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Str("path", path).Msg("construct case loader failed")
|
||||
continue
|
||||
}
|
||||
|
||||
caseConverter := TCaseConverter{
|
||||
OutputDir: outputDir,
|
||||
OutputType: outputType,
|
||||
TCase: tCase,
|
||||
}
|
||||
|
||||
// override TCase with profile
|
||||
caseConverter.overrideWithProfile(profilePath)
|
||||
|
||||
// convert TCase format to target case format
|
||||
var outputFile string
|
||||
switch outputType {
|
||||
case OutputTypeYAML:
|
||||
outputFile, err = caseConverter.ToYAML()
|
||||
case OutputTypeGoTest:
|
||||
outputFile, err = caseConverter.ToGoTest()
|
||||
case OutputTypePyTest:
|
||||
outputFile, err = caseConverter.ToPyTest()
|
||||
default:
|
||||
outputFile, err = caseConverter.ToJSON()
|
||||
}
|
||||
if err != nil {
|
||||
log.Error().Err(err).
|
||||
Str("source path", path).
|
||||
Msg("convert case failed")
|
||||
continue
|
||||
}
|
||||
outputFiles = append(outputFiles, outputFile)
|
||||
}
|
||||
log.Info().Strs("output files", outputFiles).Msg("conversion completed")
|
||||
}
|
||||
|
||||
func (c *TCaseConverter) overrideWithProfile(path string) error {
|
||||
log.Info().Str("path", path).Msg("load profile")
|
||||
profile := new(Profile)
|
||||
@@ -259,6 +224,7 @@ func (c *TCaseConverter) overrideWithProfile(path string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().Interface("profile", profile).Msg("override with profile")
|
||||
for _, step := range c.TCase.TestSteps {
|
||||
// override original headers and cookies
|
||||
if profile.Override {
|
||||
|
||||
@@ -8,11 +8,7 @@ import (
|
||||
"github.com/httprunner/httprunner/v4/hrp"
|
||||
)
|
||||
|
||||
var (
|
||||
harPath = "../../../examples/data/har/demo.har"
|
||||
harPath2 = "../../../examples/data/har/postman-echo.har"
|
||||
harProfileOverridePath = "../../../examples/data/har/profile_override.yml"
|
||||
)
|
||||
var harPath = "../../../examples/data/har/demo.har"
|
||||
|
||||
var caseHar *CaseHar
|
||||
|
||||
|
||||
@@ -6,11 +6,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
collectionPath = "../../../examples/data/postman/postman_collection.json"
|
||||
collectionProfileOverridePath = "../../../examples/data/postman/profile_override.yml"
|
||||
collectionProfilePath = "../../../examples/data/postman/profile.yml"
|
||||
)
|
||||
var collectionPath = "../../../examples/data/postman/postman_collection.json"
|
||||
|
||||
func TestLoadCollection(t *testing.T) {
|
||||
casePostman, err := loadCasePostman(collectionPath)
|
||||
|
||||
140
hrp/internal/convert/converter_test.go
Normal file
140
hrp/internal/convert/converter_test.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp"
|
||||
)
|
||||
|
||||
const (
|
||||
profilePath = "../../../examples/data/profile.yml"
|
||||
profileOverridePath = "../../../examples/data/profile_override.yml"
|
||||
)
|
||||
|
||||
func TestLoadTCase(t *testing.T) {
|
||||
tCase, err := LoadTCase(harPath)
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
if !assert.NotEmpty(t, tCase) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadHARWithProfileOverride(t *testing.T) {
|
||||
tCase, err := LoadTCase(harPath)
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
if !assert.NotEmpty(t, tCase) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
caseConverter := &TCaseConverter{
|
||||
TCase: tCase,
|
||||
}
|
||||
|
||||
// override TCase with profile
|
||||
err = caseConverter.overrideWithProfile(profileOverridePath)
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
if !assert.Equal(t,
|
||||
map[string]string{"Content-Type": "application/x-www-form-urlencoded"},
|
||||
caseConverter.TCase.TestSteps[i].Request.Headers) {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Equal(t,
|
||||
map[string]string{"UserName": "debugtalk"},
|
||||
caseConverter.TCase.TestSteps[i].Request.Cookies) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeRequestWithProfile(t *testing.T) {
|
||||
caseConverter := &TCaseConverter{
|
||||
TCase: &hrp.TCase{
|
||||
TestSteps: []*hrp.TStep{
|
||||
{
|
||||
Request: &hrp.Request{
|
||||
Method: hrp.HTTPMethod("POST"),
|
||||
Headers: map[string]string{
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
"User-Agent": "hrp",
|
||||
},
|
||||
Cookies: map[string]string{
|
||||
"abc": "123",
|
||||
"UserName": "leolee",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := caseConverter.overrideWithProfile(profilePath)
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
if !assert.Equal(t, map[string]string{
|
||||
"Content-Type": "application/x-www-form-urlencoded", "User-Agent": "hrp",
|
||||
}, caseConverter.TCase.TestSteps[0].Request.Headers) {
|
||||
t.Fatal()
|
||||
}
|
||||
if !assert.Equal(t, map[string]string{
|
||||
"UserName": "debugtalk", "abc": "123",
|
||||
}, caseConverter.TCase.TestSteps[0].Request.Cookies) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeRequestWithProfileOverride(t *testing.T) {
|
||||
caseConverter := &TCaseConverter{
|
||||
TCase: &hrp.TCase{
|
||||
TestSteps: []*hrp.TStep{
|
||||
{
|
||||
Request: &hrp.Request{
|
||||
Method: hrp.HTTPMethod("POST"),
|
||||
Headers: map[string]string{
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
"User-Agent": "hrp",
|
||||
},
|
||||
Cookies: map[string]string{
|
||||
"abc": "123",
|
||||
"UserName": "leolee",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// override TCase with profile
|
||||
err := caseConverter.overrideWithProfile(profileOverridePath)
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
if !assert.Equal(t, map[string]string{
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
}, caseConverter.TCase.TestSteps[0].Request.Headers) {
|
||||
t.Fatal()
|
||||
}
|
||||
if !assert.Equal(t, map[string]string{
|
||||
"UserName": "debugtalk",
|
||||
}, caseConverter.TCase.TestSteps[0].Request.Cookies) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user