mirror of
https://github.com/httprunner/httprunner.git
synced 2026-09-04 23:16:57 +08:00
change: make startproject as hrun sub-command, usage: hrun startproject <project_name>
This commit is contained in:
+2
-1
@@ -1,11 +1,12 @@
|
|||||||
# Release History
|
# Release History
|
||||||
|
|
||||||
## 3.0.2 (2020-04-09)
|
## 3.0.2 (2020-04-12)
|
||||||
|
|
||||||
**Changed**
|
**Changed**
|
||||||
|
|
||||||
- replace jsonschema validation with pydantic
|
- replace jsonschema validation with pydantic
|
||||||
- remove compatibility with testcase/testsuite format v1
|
- remove compatibility with testcase/testsuite format v1
|
||||||
|
- make `startproject` as hrun sub-command, usage: `hrun startproject <project_name>`
|
||||||
|
|
||||||
## 3.0.1 (2020-03-24)
|
## 3.0.1 (2020-03-24)
|
||||||
|
|
||||||
|
|||||||
+56
-34
@@ -6,64 +6,46 @@ from loguru import logger
|
|||||||
|
|
||||||
from httprunner import __description__, __version__
|
from httprunner import __description__, __version__
|
||||||
from httprunner.api import HttpRunner
|
from httprunner.api import HttpRunner
|
||||||
|
from httprunner.ext.scaffold import init_parser_scaffold, main_scaffold
|
||||||
from httprunner.report import gen_html_report
|
from httprunner.report import gen_html_report
|
||||||
from httprunner.utils import create_scaffold
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def init_parser_run(subparsers):
|
||||||
""" API test: parse command line options and run commands.
|
sub_parser_run = subparsers.add_parser(
|
||||||
"""
|
"run", help="Run HttpRunner testcases.")
|
||||||
parser = argparse.ArgumentParser(description=__description__)
|
|
||||||
parser.add_argument(
|
sub_parser_run.add_argument(
|
||||||
'-V', '--version', dest='version', action='store_true',
|
|
||||||
help="show version")
|
|
||||||
parser.add_argument(
|
|
||||||
'testfile_paths', nargs='*',
|
'testfile_paths', nargs='*',
|
||||||
help="Specify api/testcase/testsuite file paths to run.")
|
help="Specify api/testcase/testsuite file paths to run.")
|
||||||
parser.add_argument(
|
sub_parser_run.add_argument(
|
||||||
'--log-level', default='INFO',
|
'--log-level', default='INFO',
|
||||||
help="Specify logging level, default is INFO.")
|
help="Specify logging level, default is INFO.")
|
||||||
parser.add_argument(
|
sub_parser_run.add_argument(
|
||||||
'--log-file',
|
'--log-file',
|
||||||
help="Write logs to specified file path.")
|
help="Write logs to specified file path.")
|
||||||
parser.add_argument(
|
sub_parser_run.add_argument(
|
||||||
'--dot-env-path',
|
'--dot-env-path',
|
||||||
help="Specify .env file path, which is useful for keeping sensitive data.")
|
help="Specify .env file path, which is useful for keeping sensitive data.")
|
||||||
parser.add_argument(
|
sub_parser_run.add_argument(
|
||||||
'--report-template',
|
'--report-template',
|
||||||
help="Specify report template path.")
|
help="Specify report template path.")
|
||||||
parser.add_argument(
|
sub_parser_run.add_argument(
|
||||||
'--report-dir',
|
'--report-dir',
|
||||||
help="Specify report save directory.")
|
help="Specify report save directory.")
|
||||||
parser.add_argument(
|
sub_parser_run.add_argument(
|
||||||
'--report-file',
|
'--report-file',
|
||||||
help="Specify report file path, this has higher priority than specifying report dir.")
|
help="Specify report file path, this has higher priority than specifying report dir.")
|
||||||
parser.add_argument(
|
sub_parser_run.add_argument(
|
||||||
'--save-tests', action='store_true', default=False,
|
'--save-tests', action='store_true', default=False,
|
||||||
help="Save loaded/parsed/vars_out/summary json data to JSON files.")
|
help="Save loaded/parsed/vars_out/summary json data to JSON files.")
|
||||||
parser.add_argument(
|
sub_parser_run.add_argument(
|
||||||
'--failfast', action='store_true', default=False,
|
'--failfast', action='store_true', default=False,
|
||||||
help="Stop the test run on the first error or failure.")
|
help="Stop the test run on the first error or failure.")
|
||||||
parser.add_argument(
|
|
||||||
'--startproject',
|
|
||||||
help="Specify new project name.")
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
return sub_parser_run
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
|
||||||
# no argument passed
|
|
||||||
parser.print_help()
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
if args.version:
|
|
||||||
print(f"{__version__}")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
project_name = args.startproject
|
|
||||||
if project_name:
|
|
||||||
create_scaffold(project_name)
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
|
def main_run(args):
|
||||||
runner = HttpRunner(
|
runner = HttpRunner(
|
||||||
failfast=args.failfast,
|
failfast=args.failfast,
|
||||||
save_tests=args.save_tests,
|
save_tests=args.save_tests,
|
||||||
@@ -90,5 +72,45 @@ def main():
|
|||||||
sys.exit(err_code)
|
sys.exit(err_code)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
""" API test: parse command line options and run commands.
|
||||||
|
"""
|
||||||
|
parser = argparse.ArgumentParser(description=__description__)
|
||||||
|
parser.add_argument(
|
||||||
|
'-V', '--version', dest='version', action='store_true',
|
||||||
|
help="show version")
|
||||||
|
|
||||||
|
subparsers = parser.add_subparsers(help='sub-command help')
|
||||||
|
sub_parser_run = init_parser_run(subparsers)
|
||||||
|
sub_parser_scaffold = init_parser_scaffold(subparsers)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.version:
|
||||||
|
print(f"{__version__}")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if len(sys.argv) == 1:
|
||||||
|
# hrun
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
elif sys.argv[1] == "run":
|
||||||
|
# hrun run
|
||||||
|
if len(sys.argv) == 2:
|
||||||
|
sub_parser_run.print_help()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
main_run(args)
|
||||||
|
|
||||||
|
elif sys.argv[1] == "startproject":
|
||||||
|
# hrun startproject
|
||||||
|
if len(sys.argv) == 2:
|
||||||
|
sub_parser_scaffold.print_help()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
main_scaffold(args)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
|
||||||
|
def init_parser_scaffold(subparsers):
|
||||||
|
sub_parser_scaffold = subparsers.add_parser(
|
||||||
|
"startproject", help="Create a new project with template structure.")
|
||||||
|
sub_parser_scaffold.add_argument("project_name", type=str, nargs="?", help="Specify new project name.")
|
||||||
|
return sub_parser_scaffold
|
||||||
|
|
||||||
|
|
||||||
|
def create_scaffold(project_name):
|
||||||
|
""" create scaffold with specified project name.
|
||||||
|
"""
|
||||||
|
if os.path.isdir(project_name):
|
||||||
|
logger.warning(f"Folder {project_name} exists, please specify a new folder name.")
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.info(f"Start to create new project: {project_name}")
|
||||||
|
logger.info(f"CWD: {os.getcwd()}")
|
||||||
|
|
||||||
|
def create_folder(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
msg = f"created folder: {path}"
|
||||||
|
logger.info(msg)
|
||||||
|
|
||||||
|
def create_file(path, file_content=""):
|
||||||
|
with open(path, 'w') as f:
|
||||||
|
f.write(file_content)
|
||||||
|
msg = f"created file: {path}"
|
||||||
|
logger.info(msg)
|
||||||
|
|
||||||
|
demo_api_content = """
|
||||||
|
name: demo api
|
||||||
|
variables:
|
||||||
|
var1: value1
|
||||||
|
var2: value2
|
||||||
|
request:
|
||||||
|
url: /api/path/$var1
|
||||||
|
method: POST
|
||||||
|
headers:
|
||||||
|
Content-Type: "application/json"
|
||||||
|
json:
|
||||||
|
key: $var2
|
||||||
|
validate:
|
||||||
|
- eq: ["status_code", 200]
|
||||||
|
"""
|
||||||
|
demo_testcase_content = """
|
||||||
|
config:
|
||||||
|
name: "demo testcase"
|
||||||
|
variables:
|
||||||
|
device_sn: "ABC"
|
||||||
|
username: ${ENV(USERNAME)}
|
||||||
|
password: ${ENV(PASSWORD)}
|
||||||
|
base_url: "http://127.0.0.1:5000"
|
||||||
|
|
||||||
|
teststeps:
|
||||||
|
-
|
||||||
|
name: demo step 1
|
||||||
|
api: path/to/api1.yml
|
||||||
|
variables:
|
||||||
|
user_agent: 'iOS/10.3'
|
||||||
|
device_sn: $device_sn
|
||||||
|
extract:
|
||||||
|
token: content.token
|
||||||
|
validate:
|
||||||
|
- eq: ["status_code", 200]
|
||||||
|
-
|
||||||
|
name: demo step 2
|
||||||
|
api: path/to/api2.yml
|
||||||
|
variables:
|
||||||
|
token: $token
|
||||||
|
"""
|
||||||
|
demo_testsuite_content = """
|
||||||
|
config:
|
||||||
|
name: "demo testsuite"
|
||||||
|
variables:
|
||||||
|
device_sn: "XYZ"
|
||||||
|
base_url: "http://127.0.0.1:5000"
|
||||||
|
|
||||||
|
testcases:
|
||||||
|
-
|
||||||
|
name: call demo_testcase with data 1
|
||||||
|
testcase: path/to/demo_testcase.yml
|
||||||
|
variables:
|
||||||
|
device_sn: $device_sn
|
||||||
|
-
|
||||||
|
name: call demo_testcase with data 2
|
||||||
|
testcase: path/to/demo_testcase.yml
|
||||||
|
variables:
|
||||||
|
device_sn: $device_sn
|
||||||
|
"""
|
||||||
|
ignore_content = "\n".join([
|
||||||
|
".env",
|
||||||
|
"reports/*",
|
||||||
|
"__pycache__/*",
|
||||||
|
"*.pyc",
|
||||||
|
".python-version",
|
||||||
|
"logs/*"
|
||||||
|
])
|
||||||
|
demo_debugtalk_content = """
|
||||||
|
import time
|
||||||
|
|
||||||
|
def sleep(n_secs):
|
||||||
|
time.sleep(n_secs)
|
||||||
|
"""
|
||||||
|
demo_env_content = "\n".join([
|
||||||
|
"USERNAME=leolee",
|
||||||
|
"PASSWORD=123456"
|
||||||
|
])
|
||||||
|
|
||||||
|
create_folder(project_name)
|
||||||
|
create_folder(os.path.join(project_name, "api"))
|
||||||
|
create_folder(os.path.join(project_name, "testcases"))
|
||||||
|
create_folder(os.path.join(project_name, "testsuites"))
|
||||||
|
create_folder(os.path.join(project_name, "reports"))
|
||||||
|
create_file(os.path.join(project_name, "api", "demo_api.yml"), demo_api_content)
|
||||||
|
create_file(os.path.join(project_name, "testcases", "demo_testcase.yml"), demo_testcase_content)
|
||||||
|
create_file(os.path.join(project_name, "testsuites", "demo_testsuite.yml"), demo_testsuite_content)
|
||||||
|
create_file(os.path.join(project_name, "debugtalk.py"), demo_debugtalk_content)
|
||||||
|
create_file(os.path.join(project_name, ".env"), demo_env_content)
|
||||||
|
create_file(os.path.join(project_name, ".gitignore"), ignore_content)
|
||||||
|
|
||||||
|
|
||||||
|
def main_scaffold(args):
|
||||||
|
create_scaffold(args.project_name)
|
||||||
|
sys.exit(0)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from httprunner.ext.scaffold import create_scaffold
|
||||||
|
|
||||||
|
|
||||||
|
class TestUtils(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_create_scaffold(self):
|
||||||
|
project_name = "projectABC"
|
||||||
|
create_scaffold(project_name)
|
||||||
|
self.assertTrue(os.path.isdir(os.path.join(project_name, "api")))
|
||||||
|
self.assertTrue(os.path.isdir(os.path.join(project_name, "testcases")))
|
||||||
|
self.assertTrue(os.path.isdir(os.path.join(project_name, "testsuites")))
|
||||||
|
self.assertTrue(os.path.isdir(os.path.join(project_name, "reports")))
|
||||||
|
self.assertTrue(os.path.isfile(os.path.join(project_name, "debugtalk.py")))
|
||||||
|
self.assertTrue(os.path.isfile(os.path.join(project_name, ".env")))
|
||||||
|
shutil.rmtree(project_name)
|
||||||
@@ -349,119 +349,6 @@ def print_info(info_mapping):
|
|||||||
logger.info(content)
|
logger.info(content)
|
||||||
|
|
||||||
|
|
||||||
def create_scaffold(project_name):
|
|
||||||
""" create scaffold with specified project name.
|
|
||||||
"""
|
|
||||||
if os.path.isdir(project_name):
|
|
||||||
logger.warning(f"Folder {project_name} exists, please specify a new folder name.")
|
|
||||||
return
|
|
||||||
|
|
||||||
logger.info(f"Start to create new project: {project_name}")
|
|
||||||
logger.info(f"CWD: {os.getcwd()}")
|
|
||||||
|
|
||||||
def create_folder(path):
|
|
||||||
os.makedirs(path)
|
|
||||||
msg = f"created folder: {path}"
|
|
||||||
logger.info(msg)
|
|
||||||
|
|
||||||
def create_file(path, file_content=""):
|
|
||||||
with open(path, 'w') as f:
|
|
||||||
f.write(file_content)
|
|
||||||
msg = f"created file: {path}"
|
|
||||||
logger.info(msg)
|
|
||||||
|
|
||||||
demo_api_content = """
|
|
||||||
name: demo api
|
|
||||||
variables:
|
|
||||||
var1: value1
|
|
||||||
var2: value2
|
|
||||||
request:
|
|
||||||
url: /api/path/$var1
|
|
||||||
method: POST
|
|
||||||
headers:
|
|
||||||
Content-Type: "application/json"
|
|
||||||
json:
|
|
||||||
key: $var2
|
|
||||||
validate:
|
|
||||||
- eq: ["status_code", 200]
|
|
||||||
"""
|
|
||||||
demo_testcase_content = """
|
|
||||||
config:
|
|
||||||
name: "demo testcase"
|
|
||||||
variables:
|
|
||||||
device_sn: "ABC"
|
|
||||||
username: ${ENV(USERNAME)}
|
|
||||||
password: ${ENV(PASSWORD)}
|
|
||||||
base_url: "http://127.0.0.1:5000"
|
|
||||||
|
|
||||||
teststeps:
|
|
||||||
-
|
|
||||||
name: demo step 1
|
|
||||||
api: path/to/api1.yml
|
|
||||||
variables:
|
|
||||||
user_agent: 'iOS/10.3'
|
|
||||||
device_sn: $device_sn
|
|
||||||
extract:
|
|
||||||
- token: content.token
|
|
||||||
validate:
|
|
||||||
- eq: ["status_code", 200]
|
|
||||||
-
|
|
||||||
name: demo step 2
|
|
||||||
api: path/to/api2.yml
|
|
||||||
variables:
|
|
||||||
token: $token
|
|
||||||
"""
|
|
||||||
demo_testsuite_content = """
|
|
||||||
config:
|
|
||||||
name: "demo testsuite"
|
|
||||||
variables:
|
|
||||||
device_sn: "XYZ"
|
|
||||||
base_url: "http://127.0.0.1:5000"
|
|
||||||
|
|
||||||
testcases:
|
|
||||||
-
|
|
||||||
name: call demo_testcase with data 1
|
|
||||||
testcase: path/to/demo_testcase.yml
|
|
||||||
variables:
|
|
||||||
device_sn: $device_sn
|
|
||||||
-
|
|
||||||
name: call demo_testcase with data 2
|
|
||||||
testcase: path/to/demo_testcase.yml
|
|
||||||
variables:
|
|
||||||
device_sn: $device_sn
|
|
||||||
"""
|
|
||||||
ignore_content = "\n".join([
|
|
||||||
".env",
|
|
||||||
"reports/*",
|
|
||||||
"__pycache__/*",
|
|
||||||
"*.pyc",
|
|
||||||
".python-version",
|
|
||||||
"logs/*"
|
|
||||||
])
|
|
||||||
demo_debugtalk_content = """
|
|
||||||
import time
|
|
||||||
|
|
||||||
def sleep(n_secs):
|
|
||||||
time.sleep(n_secs)
|
|
||||||
"""
|
|
||||||
demo_env_content = "\n".join([
|
|
||||||
"USERNAME=leolee",
|
|
||||||
"PASSWORD=123456"
|
|
||||||
])
|
|
||||||
|
|
||||||
create_folder(project_name)
|
|
||||||
create_folder(os.path.join(project_name, "api"))
|
|
||||||
create_folder(os.path.join(project_name, "testcases"))
|
|
||||||
create_folder(os.path.join(project_name, "testsuites"))
|
|
||||||
create_folder(os.path.join(project_name, "reports"))
|
|
||||||
create_file(os.path.join(project_name, "api", "demo_api.yml"), demo_api_content)
|
|
||||||
create_file(os.path.join(project_name, "testcases", "demo_testcase.yml"), demo_testcase_content)
|
|
||||||
create_file(os.path.join(project_name, "testsuites", "demo_testsuite.yml"), demo_testsuite_content)
|
|
||||||
create_file(os.path.join(project_name, "debugtalk.py"), demo_debugtalk_content)
|
|
||||||
create_file(os.path.join(project_name, ".env"), demo_env_content)
|
|
||||||
create_file(os.path.join(project_name, ".gitignore"), ignore_content)
|
|
||||||
|
|
||||||
|
|
||||||
def gen_cartesian_product(*args):
|
def gen_cartesian_product(*args):
|
||||||
""" generate cartesian product for lists
|
""" generate cartesian product for lists
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import shutil
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from httprunner import exceptions, loader, utils
|
from httprunner import exceptions, loader, utils
|
||||||
@@ -210,17 +209,6 @@ class TestUtils(unittest.TestCase):
|
|||||||
self.assertEqual(id(new_data["c"]), id(data["c"]))
|
self.assertEqual(id(new_data["c"]), id(data["c"]))
|
||||||
# self.assertEqual(id(new_data["d"]), id(data["d"]))
|
# self.assertEqual(id(new_data["d"]), id(data["d"]))
|
||||||
|
|
||||||
def test_create_scaffold(self):
|
|
||||||
project_name = "projectABC"
|
|
||||||
utils.create_scaffold(project_name)
|
|
||||||
self.assertTrue(os.path.isdir(os.path.join(project_name, "api")))
|
|
||||||
self.assertTrue(os.path.isdir(os.path.join(project_name, "testcases")))
|
|
||||||
self.assertTrue(os.path.isdir(os.path.join(project_name, "testsuites")))
|
|
||||||
self.assertTrue(os.path.isdir(os.path.join(project_name, "reports")))
|
|
||||||
self.assertTrue(os.path.isfile(os.path.join(project_name, "debugtalk.py")))
|
|
||||||
self.assertTrue(os.path.isfile(os.path.join(project_name, ".env")))
|
|
||||||
shutil.rmtree(project_name)
|
|
||||||
|
|
||||||
def test_cartesian_product_one(self):
|
def test_cartesian_product_one(self):
|
||||||
parameters_content_list = [
|
parameters_content_list = [
|
||||||
[
|
[
|
||||||
|
|||||||
Reference in New Issue
Block a user