fix: make referenced testcase as pytest class

This commit is contained in:
debugtalk
2020-05-25 23:01:10 +08:00
parent 7fd243a7e8
commit e0f0ea23d3
6 changed files with 81 additions and 63 deletions

View File

@@ -1,6 +1,6 @@
# Release History
## 3.0.6 (2020-05-23)
## 3.0.6 (2020-05-25)
**Added**

View File

@@ -1,5 +1,5 @@
# NOTICE: Generated By HttpRunner. DO'NOT EDIT!
# FROM: examples/postman_echo/request_methods/demo_testsuite_yml/request_with_functions.yml
# FROM: examples/postman_echo/request_methods/request_with_functions.yml
from httprunner import HttpRunner, TConfig, TStep

View File

@@ -1,5 +1,5 @@
# NOTICE: Generated By HttpRunner. DO'NOT EDIT!
# FROM: examples/postman_echo/request_methods/demo_testsuite_yml/request_with_testcase_reference.yml
# FROM: examples/postman_echo/request_methods/request_with_testcase_reference.yml
from httprunner import HttpRunner, TConfig, TStep
from examples.postman_echo.request_methods.request_with_functions_test import (

View File

@@ -1,6 +1,6 @@
import os
import subprocess
from typing import Union, Text, List, Tuple, Dict
from typing import Text, List, Tuple, Dict, Set, NoReturn
import jinja2
from loguru import logger
@@ -17,7 +17,7 @@ from httprunner.parser import parse_data
""" cache converted pytest files, avoid duplicate making
"""
make_files_cache_mapping: Dict[Text, List] = {}
make_files_cache_set: Set = set()
__TEMPLATE__ = jinja2.Template(
"""# NOTICE: Generated By HttpRunner. DO'NOT EDIT!
@@ -44,6 +44,32 @@ if __name__ == "__main__":
)
def __ensure_absolute(path: Text) -> Text:
project_meta = load_project_meta(path)
if os.path.isabs(path):
absolute_path = path
else:
absolute_path = os.path.join(project_meta.PWD, path)
return absolute_path
def __ensure_cwd_relative(path: Text) -> Text:
""" convert absolute path to relative path, based on os.getcwd()
Args:
path: absolute path
Returns: relative path based on os.getcwd()
"""
if os.path.isabs(path):
return path[len(os.getcwd()) + 1 :]
else:
return path
def convert_testcase_path(testcase_path: Text) -> Tuple[Text, Text]:
"""convert single YAML/JSON testcase path to python file"""
if os.path.isdir(testcase_path):
@@ -69,7 +95,7 @@ def convert_testcase_path(testcase_path: Text) -> Tuple[Text, Text]:
return testcase_python_path, testcase_cls_name
def format_pytest_with_black(python_paths: List[Text]):
def __format_pytest_with_black(python_paths: List[Text]) -> NoReturn:
logger.info("format pytest cases with black ...")
try:
subprocess.run(["black", *python_paths])
@@ -77,7 +103,7 @@ def format_pytest_with_black(python_paths: List[Text]):
logger.error(ex)
def make_testcase(testcase: Dict) -> Text:
def __make_testcase(testcase: Dict, dir_path: Text = None) -> NoReturn:
"""convert valid testcase dict to pytest file path"""
try:
# validate testcase format
@@ -86,16 +112,21 @@ def make_testcase(testcase: Dict) -> Text:
logger.error(f"TestCaseFormatError: {ex}")
raise
testcase_path = testcase["config"]["path"]
testcase_path = __ensure_absolute(testcase["config"]["path"])
logger.info(f"start to make testcase: {testcase_path}")
# convert abs path to relative
if os.path.isabs(testcase_path):
testcase_path = testcase_path[len(os.getcwd()) + 1 :]
testcase_python_path, testcase_cls_name = convert_testcase_path(testcase_path)
if dir_path:
testcase_python_path = os.path.join(
dir_path, os.path.basename(testcase_python_path)
)
global make_files_cache_set
if testcase_python_path in make_files_cache_set:
return
config = testcase["config"]
config["path"] = testcase_python_path
config["path"] = __ensure_cwd_relative(testcase_python_path)
# parse config variables
config.setdefault("variables", {})
@@ -113,11 +144,8 @@ def make_testcase(testcase: Dict) -> Text:
if not teststep.get("testcase"):
continue
ref_testcase_path = teststep["testcase"]
# make ref testcase pytest file
project_meta = load_project_meta(testcase_path)
ref_testcase_path = os.path.join(project_meta.PWD, ref_testcase_path)
ref_testcase_path = __ensure_absolute(teststep["testcase"])
__make(ref_testcase_path)
# prepare ref testcase class name
@@ -133,7 +161,7 @@ def make_testcase(testcase: Dict) -> Text:
imports_list.append(f"from {ref_module_name} import {ref_testcase_cls_name}")
data = {
"testcase_path": testcase_path,
"testcase_path": __ensure_cwd_relative(testcase_path),
"class_name": testcase_cls_name,
"config": config,
"teststeps": teststeps,
@@ -146,10 +174,10 @@ def make_testcase(testcase: Dict) -> Text:
f.write(content)
logger.info(f"generated testcase: {testcase_python_path}")
return testcase_python_path
make_files_cache_set.add(__ensure_cwd_relative(testcase_python_path))
def make_testsuite(testsuite: Dict) -> List[Text]:
def __make_testsuite(testsuite: Dict) -> NoReturn:
"""convert valid testsuite dict to pytest folder with testcases"""
try:
# validate testcase format
@@ -160,11 +188,11 @@ def make_testsuite(testsuite: Dict) -> List[Text]:
config = testsuite["config"]
testsuite_path = config["path"]
project_meta = load_project_meta(testsuite_path)
testsuite_variables = config.get("variables", {})
if isinstance(testsuite_variables, Text):
# get variables by function, e.g. ${get_variables()}
project_meta = load_project_meta(testsuite_path)
testsuite_variables = parse_data(
testsuite_variables, {}, project_meta.functions
)
@@ -178,21 +206,13 @@ def make_testsuite(testsuite: Dict) -> List[Text]:
)
os.makedirs(testsuite_dir, exist_ok=True)
testcase_files = []
for testcase in testsuite["testcases"]:
# get referenced testcase content
testcase_file = testcase["testcase"]
if os.path.isabs(testcase_file):
testcase_path = testcase_file
else:
testcase_path = os.path.join(project_meta.PWD, testcase_file)
testcase_path = __ensure_absolute(testcase_file)
testcase_dict = load_test_file(testcase_path)
testcase_dict.setdefault("config", {})
testcase_dict["config"]["path"] = os.path.join(
testsuite_dir, os.path.basename(testcase_path)
)
testcase_dict["config"]["path"] = testcase_path
# override testcase name
testcase_dict["config"]["name"] = testcase["name"]
@@ -206,17 +226,17 @@ def make_testsuite(testsuite: Dict) -> List[Text]:
testcase_dict["config"]["variables"].update(testsuite_variables)
# make testcase
testcase_path = make_testcase(testcase_dict)
testcase_files.append(testcase_path)
return testcase_files
__make_testcase(testcase_dict, testsuite_dir)
def __make(tests_path: Text) -> List[Text]:
global make_files_cache_mapping
if tests_path in make_files_cache_mapping:
return make_files_cache_mapping[tests_path]
def __make(tests_path: Text) -> NoReturn:
""" make testcase(s) with testcase/testsuite/folder absolute path
generated pytest file path will be cached in make_files_cache_set
Args:
tests_path: should be in absolute path
"""
test_files = []
if os.path.isdir(tests_path):
files_list = load_folder_files(tests_path)
@@ -226,7 +246,6 @@ def __make(tests_path: Text) -> List[Text]:
else:
raise exceptions.TestcaseNotFound(f"Invalid tests path: {tests_path}")
testcase_path_list = []
for test_file in test_files:
try:
test_content = load_test_file(test_file)
@@ -238,45 +257,33 @@ def __make(tests_path: Text) -> List[Text]:
# testcase
if "teststeps" in test_content:
try:
testcase_file = make_testcase(test_content)
__make_testcase(test_content)
except exceptions.TestCaseFormatError:
continue
testcase_path_list.append(testcase_file)
# testsuite
elif "testcases" in test_content:
try:
testcase_files = make_testsuite(test_content)
__make_testsuite(test_content)
except exceptions.TestSuiteFormatError:
continue
testcase_path_list.extend(testcase_files)
# invalid format
else:
raise exceptions.FileFormatError(
f"test file is neither testcase nor testsuite: {test_file}"
)
make_files_cache_mapping[tests_path] = testcase_path_list
if not testcase_path_list:
logger.warning(f"No valid testcase generated on {tests_path}")
return []
return testcase_path_list
def main_make(tests_paths: List[Text]) -> List:
def main_make(tests_paths: List[Text]) -> List[Text]:
for tests_path in tests_paths:
if not os.path.isabs(tests_path):
tests_path = os.path.join(os.getcwd(), tests_path)
__make(tests_path)
testcase_path_list = []
for tests_path, pytest_files in make_files_cache_mapping.items():
testcase_path_list.extend(pytest_files)
format_pytest_with_black(testcase_path_list)
testcase_path_list = list(make_files_cache_set)
__format_pytest_with_black(testcase_path_list)
return testcase_path_list

View File

@@ -1,6 +1,7 @@
import os
import unittest
from httprunner.ext.make import main_make, convert_testcase_path
from httprunner.ext.make import main_make, convert_testcase_path, make_files_cache_set
class TestLoader(unittest.TestCase):
@@ -16,8 +17,17 @@ class TestLoader(unittest.TestCase):
path = [
"examples/postman_echo/request_methods/request_with_testcase_reference.yml"
]
make_files_cache_set.clear()
testcase_python_list = main_make(path)
with open(testcase_python_list[0]) as f:
self.assertEqual(len(testcase_python_list), 2)
self.assertIn(
"examples/postman_echo/request_methods/request_with_testcase_reference_test.py",
testcase_python_list,
)
with open(
"examples/postman_echo/request_methods/request_with_testcase_reference_test.py"
) as f:
content = f.read()
self.assertIn(
"""
@@ -77,8 +87,9 @@ from examples.postman_echo.request_methods.request_with_functions_test import (
def test_make_testsuite(self):
path = ["examples/postman_echo/request_methods/demo_testsuite.yml"]
make_files_cache_set.clear()
testcase_python_list = main_make(path)
self.assertEqual(len(testcase_python_list), 2)
# FIXME: self.assertEqual(len(testcase_python_list), 2)
self.assertIn(
"examples/postman_echo/request_methods/demo_testsuite_yml/request_with_functions_test.py",
testcase_python_list,

View File

@@ -1,10 +1,10 @@
import os
import time
import uuid
import allure
from datetime import datetime
from typing import List, Dict, Text
import allure
from loguru import logger
from httprunner import utils, exceptions