mirror of
https://github.com/httprunner/httprunner.git
synced 2026-06-06 00:09:37 +08:00
Merge pull request #905 from httprunner/v3
## 3.0.5 (2020-05-22) **Added** - feat: each testcase has an unique id in uuid4 format - feat: add default header `HRUN-Request-ID` for each testcase #721 - feat: builtin allure report - feat: dump log for each testcase **Fixed** - fix: ensure referenced testcase share the same session **Changed** - change: remove default added `-s` option for hrun
This commit is contained in:
13
.github/workflows/integration_test.yml
vendored
13
.github/workflows/integration_test.yml
vendored
@@ -30,14 +30,13 @@ jobs:
|
|||||||
poetry build
|
poetry build
|
||||||
ls dist/*.whl | xargs pip install # test installation
|
ls dist/*.whl | xargs pip install # test installation
|
||||||
hrun -V
|
hrun -V
|
||||||
hrun run -h
|
har2case -h
|
||||||
hrun startproject -h
|
httprunner run -h
|
||||||
hrun har2case -h
|
httprunner startproject -h
|
||||||
pip install locustio
|
httprunner har2case -h
|
||||||
hrun locusts -h
|
|
||||||
- name: Run smoketest - postman echo
|
- name: Run smoketest - postman echo
|
||||||
run: |
|
run: |
|
||||||
hrun examples/postman_echo/request_methods
|
hrun -s examples/postman_echo/request_methods
|
||||||
- name: Run smoketest - httpbin
|
- name: Run smoketest - httpbin
|
||||||
run: |
|
run: |
|
||||||
hrun examples/httpbin/
|
hrun -s examples/httpbin/
|
||||||
|
|||||||
@@ -1,5 +1,22 @@
|
|||||||
# Release History
|
# Release History
|
||||||
|
|
||||||
|
## 3.0.5 (2020-05-22)
|
||||||
|
|
||||||
|
**Added**
|
||||||
|
|
||||||
|
- feat: each testcase has an unique id in uuid4 format
|
||||||
|
- feat: add default header `HRUN-Request-ID` for each testcase #721
|
||||||
|
- feat: builtin allure report
|
||||||
|
- feat: dump log for each testcase
|
||||||
|
|
||||||
|
**Fixed**
|
||||||
|
|
||||||
|
- fix: ensure referenced testcase share the same session
|
||||||
|
|
||||||
|
**Changed**
|
||||||
|
|
||||||
|
- change: remove default added `-s` option for hrun
|
||||||
|
|
||||||
## 3.0.4 (2020-05-19)
|
## 3.0.4 (2020-05-19)
|
||||||
|
|
||||||
**Added**
|
**Added**
|
||||||
|
|||||||
2
examples/postman_echo/conftest.py
Normal file
2
examples/postman_echo/conftest.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
__version__ = "3.0.4"
|
__version__ = "3.0.5"
|
||||||
__description__ = "One-stop solution for HTTP(S) testing."
|
__description__ = "One-stop solution for HTTP(S) testing."
|
||||||
|
|
||||||
from httprunner.runner import HttpRunner
|
from httprunner.runner import HttpRunner
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import sys
|
|||||||
import pytest
|
import pytest
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from httprunner import __description__, __version__, exceptions
|
from httprunner import __description__, __version__
|
||||||
from httprunner.ext.har2case import init_har2case_parser, main_har2case
|
from httprunner.ext.har2case import init_har2case_parser, main_har2case
|
||||||
from httprunner.ext.make import init_make_parser, main_make, convert_testcase_path
|
from httprunner.ext.make import init_make_parser, main_make
|
||||||
from httprunner.ext.scaffold import init_parser_scaffold, main_scaffold
|
from httprunner.ext.scaffold import init_parser_scaffold, main_scaffold
|
||||||
|
|
||||||
|
|
||||||
@@ -40,9 +40,6 @@ def main_run(extra_args):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
extra_args_new.extend(testcase_path_list)
|
extra_args_new.extend(testcase_path_list)
|
||||||
if "-s" not in extra_args_new:
|
|
||||||
extra_args_new.insert(0, "-s")
|
|
||||||
|
|
||||||
pytest.main(extra_args_new)
|
pytest.main(extra_args_new)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import io
|
|||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from httprunner.cli import main
|
from httprunner.cli import main
|
||||||
|
|
||||||
|
|
||||||
@@ -36,3 +38,11 @@ class TestCli(unittest.TestCase):
|
|||||||
from httprunner import __description__
|
from httprunner import __description__
|
||||||
|
|
||||||
self.assertIn(__description__, self.captured_output.getvalue().strip())
|
self.assertIn(__description__, self.captured_output.getvalue().strip())
|
||||||
|
|
||||||
|
def test_debug_pytest(self):
|
||||||
|
pytest.main(
|
||||||
|
[
|
||||||
|
"-s",
|
||||||
|
"examples/postman_echo/request_methods/request_with_variables_test.py",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ def get_req_resp_record(resp_obj: Response) -> ReqRespData:
|
|||||||
|
|
||||||
# record actual request info
|
# record actual request info
|
||||||
request_headers = dict(resp_obj.request.headers)
|
request_headers = dict(resp_obj.request.headers)
|
||||||
|
request_cookies = dict(resp_obj.request._cookies)
|
||||||
request_body = resp_obj.request.body
|
request_body = resp_obj.request.body
|
||||||
try:
|
try:
|
||||||
request_body = json.loads(request_body)
|
request_body = json.loads(request_body)
|
||||||
@@ -57,6 +58,7 @@ def get_req_resp_record(resp_obj: Response) -> ReqRespData:
|
|||||||
method=resp_obj.request.method,
|
method=resp_obj.request.method,
|
||||||
url=resp_obj.request.url,
|
url=resp_obj.request.url,
|
||||||
headers=request_headers,
|
headers=request_headers,
|
||||||
|
cookies=request_cookies,
|
||||||
body=request_body,
|
body=request_body,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -192,7 +194,7 @@ class HttpSession(requests.Session):
|
|||||||
logger.info(
|
logger.info(
|
||||||
f"status_code: {response.status_code}, "
|
f"status_code: {response.status_code}, "
|
||||||
f"response_time(ms): {response_time_ms} ms, "
|
f"response_time(ms): {response_time_ms} ms, "
|
||||||
f"response_length: {content_size} bytes\n"
|
f"response_length: {content_size} bytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|||||||
@@ -410,6 +410,11 @@ def load_project_meta(test_path: Text) -> ProjectMeta:
|
|||||||
environments and debugtalk.py functions.
|
environments and debugtalk.py functions.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
project_meta = ProjectMeta()
|
||||||
|
|
||||||
|
if not test_path:
|
||||||
|
return project_meta
|
||||||
|
|
||||||
if test_path in project_meta_cached_mapping:
|
if test_path in project_meta_cached_mapping:
|
||||||
return project_meta_cached_mapping[test_path]
|
return project_meta_cached_mapping[test_path]
|
||||||
|
|
||||||
@@ -417,8 +422,6 @@ def load_project_meta(test_path: Text) -> ProjectMeta:
|
|||||||
test_path
|
test_path
|
||||||
)
|
)
|
||||||
|
|
||||||
project_meta = ProjectMeta()
|
|
||||||
|
|
||||||
# load .env file
|
# load .env file
|
||||||
# NOTICE:
|
# NOTICE:
|
||||||
# environment variable maybe loaded in debugtalk.py
|
# environment variable maybe loaded in debugtalk.py
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
import uuid
|
||||||
|
import allure
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import List, Dict, Text
|
from typing import List, Dict, Text
|
||||||
|
|
||||||
@@ -31,11 +33,15 @@ class HttpRunner(object):
|
|||||||
|
|
||||||
success: bool = True # indicate testcase execution result
|
success: bool = True # indicate testcase execution result
|
||||||
__project_meta: ProjectMeta = None
|
__project_meta: ProjectMeta = None
|
||||||
|
__case_id: Text = ""
|
||||||
__step_datas: List[StepData] = None
|
__step_datas: List[StepData] = None
|
||||||
__session: HttpSession = None
|
__session: HttpSession = None
|
||||||
__session_variables: VariablesMapping = {}
|
__session_variables: VariablesMapping = {}
|
||||||
__start_at = 0
|
# time
|
||||||
__duration = 0
|
__start_at: float = 0
|
||||||
|
__duration: float = 0
|
||||||
|
# log
|
||||||
|
__log_path: Text = ""
|
||||||
|
|
||||||
def with_project_meta(self, project_meta: ProjectMeta) -> "HttpRunner":
|
def with_project_meta(self, project_meta: ProjectMeta) -> "HttpRunner":
|
||||||
self.__project_meta = project_meta
|
self.__project_meta = project_meta
|
||||||
@@ -45,6 +51,10 @@ class HttpRunner(object):
|
|||||||
self.__session = session
|
self.__session = session
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def with_case_id(self, case_id: Text) -> "HttpRunner":
|
||||||
|
self.__case_id = case_id
|
||||||
|
return self
|
||||||
|
|
||||||
def with_variables(self, variables: VariablesMapping) -> "HttpRunner":
|
def with_variables(self, variables: VariablesMapping) -> "HttpRunner":
|
||||||
self.__session_variables = variables
|
self.__session_variables = variables
|
||||||
return self
|
return self
|
||||||
@@ -60,6 +70,10 @@ class HttpRunner(object):
|
|||||||
parsed_request_dict = parse_data(
|
parsed_request_dict = parse_data(
|
||||||
request_dict, step.variables, self.__project_meta.functions
|
request_dict, step.variables, self.__project_meta.functions
|
||||||
)
|
)
|
||||||
|
parsed_request_dict["headers"].setdefault(
|
||||||
|
"HRUN-Request-ID",
|
||||||
|
f"HRUN-{self.__case_id}-{str(int(time.time() * 1000))[-6:]}",
|
||||||
|
)
|
||||||
|
|
||||||
# prepare arguments
|
# prepare arguments
|
||||||
method = parsed_request_dict.pop("method")
|
method = parsed_request_dict.pop("method")
|
||||||
@@ -68,7 +82,6 @@ class HttpRunner(object):
|
|||||||
parsed_request_dict["json"] = parsed_request_dict.pop("req_json", {})
|
parsed_request_dict["json"] = parsed_request_dict.pop("req_json", {})
|
||||||
|
|
||||||
# request
|
# request
|
||||||
self.__session = self.__session or HttpSession()
|
|
||||||
resp = self.__session.request(method, url, **parsed_request_dict)
|
resp = self.__session.request(method, url, **parsed_request_dict)
|
||||||
resp_obj = ResponseObject(resp)
|
resp_obj = ResponseObject(resp)
|
||||||
|
|
||||||
@@ -132,6 +145,7 @@ class HttpRunner(object):
|
|||||||
case_result = (
|
case_result = (
|
||||||
HttpRunner()
|
HttpRunner()
|
||||||
.with_session(self.__session)
|
.with_session(self.__session)
|
||||||
|
.with_case_id(self.__case_id)
|
||||||
.with_variables(step_variables)
|
.with_variables(step_variables)
|
||||||
.run_path(ref_testcase_path)
|
.run_path(ref_testcase_path)
|
||||||
)
|
)
|
||||||
@@ -159,32 +173,32 @@ class HttpRunner(object):
|
|||||||
logger.info(f"run step end: {step.name} <<<<<<\n")
|
logger.info(f"run step end: {step.name} <<<<<<\n")
|
||||||
return step_data.export
|
return step_data.export
|
||||||
|
|
||||||
|
def __parse_config(self, config: TConfig):
|
||||||
|
config.variables.update(self.__session_variables)
|
||||||
|
config.variables = parse_variables_mapping(
|
||||||
|
config.variables, self.__project_meta.functions
|
||||||
|
)
|
||||||
|
config.name = parse_data(
|
||||||
|
config.name, config.variables, self.__project_meta.functions
|
||||||
|
)
|
||||||
|
config.base_url = parse_data(
|
||||||
|
config.base_url, config.variables, self.__project_meta.functions
|
||||||
|
)
|
||||||
|
|
||||||
def run(self, testcase: TestCase):
|
def run(self, testcase: TestCase):
|
||||||
"""main entrance"""
|
"""run testcase"""
|
||||||
self.config = testcase.config
|
self.config = testcase.config
|
||||||
self.teststeps = testcase.teststeps
|
self.teststeps = testcase.teststeps
|
||||||
self.config.variables.update(self.__session_variables)
|
|
||||||
|
|
||||||
if self.config.path:
|
# prepare
|
||||||
self.__project_meta = load_project_meta(self.config.path)
|
self.__project_meta = self.__project_meta or load_project_meta(self.config.path)
|
||||||
elif not self.__project_meta:
|
self.__parse_config(self.config)
|
||||||
self.__project_meta = ProjectMeta()
|
|
||||||
|
|
||||||
def parse_config(config: TConfig):
|
|
||||||
config.variables = parse_variables_mapping(
|
|
||||||
config.variables, self.__project_meta.functions
|
|
||||||
)
|
|
||||||
config.name = parse_data(
|
|
||||||
config.name, config.variables, self.__project_meta.functions
|
|
||||||
)
|
|
||||||
config.base_url = parse_data(
|
|
||||||
config.base_url, config.variables, self.__project_meta.functions
|
|
||||||
)
|
|
||||||
|
|
||||||
parse_config(self.config)
|
|
||||||
self.__start_at = time.time()
|
self.__start_at = time.time()
|
||||||
self.__step_datas: List[StepData] = []
|
self.__step_datas: List[StepData] = []
|
||||||
|
self.__session = self.__session or HttpSession()
|
||||||
self.__session_variables = {}
|
self.__session_variables = {}
|
||||||
|
|
||||||
|
# run teststeps
|
||||||
for step in self.teststeps:
|
for step in self.teststeps:
|
||||||
# update with config variables
|
# update with config variables
|
||||||
step.variables.update(self.config.variables)
|
step.variables.update(self.config.variables)
|
||||||
@@ -195,7 +209,8 @@ class HttpRunner(object):
|
|||||||
step.variables, self.__project_meta.functions
|
step.variables, self.__project_meta.functions
|
||||||
)
|
)
|
||||||
# run step
|
# run step
|
||||||
extract_mapping = self.__run_step(step)
|
with allure.step(f"step: {step.name}"):
|
||||||
|
extract_mapping = self.__run_step(step)
|
||||||
# save extracted variables to session variables
|
# save extracted variables to session variables
|
||||||
self.__session_variables.update(extract_mapping)
|
self.__session_variables.update(extract_mapping)
|
||||||
|
|
||||||
@@ -231,6 +246,7 @@ class HttpRunner(object):
|
|||||||
return TestCaseSummary(
|
return TestCaseSummary(
|
||||||
name=self.config.name,
|
name=self.config.name,
|
||||||
success=self.success,
|
success=self.success,
|
||||||
|
case_id=self.__case_id,
|
||||||
time=TestCaseTime(
|
time=TestCaseTime(
|
||||||
start_at=self.__start_at,
|
start_at=self.__start_at,
|
||||||
start_at_iso_format=start_at_iso_format,
|
start_at_iso_format=start_at_iso_format,
|
||||||
@@ -239,9 +255,36 @@ class HttpRunner(object):
|
|||||||
in_out=TestCaseInOut(
|
in_out=TestCaseInOut(
|
||||||
vars=self.config.variables, export=self.get_export_variables()
|
vars=self.config.variables, export=self.get_export_variables()
|
||||||
),
|
),
|
||||||
|
log=self.__log_path,
|
||||||
step_datas=self.__step_datas,
|
step_datas=self.__step_datas,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_start(self):
|
def test_start(self):
|
||||||
"""discovered by pytest"""
|
"""main entrance, discovered by pytest"""
|
||||||
return self.run(TestCase(config=self.config, teststeps=self.teststeps))
|
self.__case_id = self.__case_id or str(uuid.uuid4())
|
||||||
|
self.__log_path = self.__log_path or os.path.join(
|
||||||
|
"logs", f"{self.__case_id}.run.log"
|
||||||
|
)
|
||||||
|
log_handler = logger.add(self.__log_path, level="DEBUG")
|
||||||
|
|
||||||
|
# parse config name
|
||||||
|
self.__project_meta = self.__project_meta or load_project_meta(self.config.path)
|
||||||
|
variables = self.config.variables
|
||||||
|
variables.update(self.__session_variables)
|
||||||
|
self.config.name = parse_data(
|
||||||
|
self.config.name, variables, self.__project_meta.functions
|
||||||
|
)
|
||||||
|
|
||||||
|
# update allure report meta
|
||||||
|
allure.dynamic.title(self.config.name)
|
||||||
|
allure.dynamic.description(f"TestCase ID: {self.__case_id}")
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"Start to run testcase: {self.config.name}, TestCase ID: {self.__case_id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return self.run(TestCase(config=self.config, teststeps=self.teststeps))
|
||||||
|
finally:
|
||||||
|
logger.remove(log_handler)
|
||||||
|
logger.info(f"generate testcase log: {self.__log_path}")
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ BaseUrl = Union[HttpUrl, Text]
|
|||||||
VariablesMapping = Dict[Text, Any]
|
VariablesMapping = Dict[Text, Any]
|
||||||
FunctionsMapping = Dict[Text, Callable]
|
FunctionsMapping = Dict[Text, Callable]
|
||||||
Headers = Dict[Text, Text]
|
Headers = Dict[Text, Text]
|
||||||
|
Cookies = Dict[Text, Text]
|
||||||
Verify = bool
|
Verify = bool
|
||||||
Hook = List[Text]
|
Hook = List[Text]
|
||||||
Export = List[Text]
|
Export = List[Text]
|
||||||
@@ -53,7 +54,7 @@ class Request(BaseModel):
|
|||||||
headers: Headers = {}
|
headers: Headers = {}
|
||||||
req_json: Dict = Field({}, alias="json")
|
req_json: Dict = Field({}, alias="json")
|
||||||
data: Union[Text, Dict[Text, Any]] = ""
|
data: Union[Text, Dict[Text, Any]] = ""
|
||||||
cookies: Dict[Text, Text] = {}
|
cookies: Cookies = {}
|
||||||
timeout: int = 120
|
timeout: int = 120
|
||||||
allow_redirects: bool = True
|
allow_redirects: bool = True
|
||||||
verify: Verify = False
|
verify: Verify = False
|
||||||
@@ -108,15 +109,15 @@ class RequestData(BaseModel):
|
|||||||
method: MethodEnum = MethodEnum.GET
|
method: MethodEnum = MethodEnum.GET
|
||||||
url: Url
|
url: Url
|
||||||
headers: Headers = {}
|
headers: Headers = {}
|
||||||
# TODO: add cookies
|
cookies: Cookies = {}
|
||||||
body: Union[Text, bytes, Dict, None] = {}
|
body: Union[Text, bytes, Dict, None] = {}
|
||||||
|
|
||||||
|
|
||||||
class ResponseData(BaseModel):
|
class ResponseData(BaseModel):
|
||||||
status_code: int
|
status_code: int
|
||||||
cookies: Dict
|
|
||||||
encoding: Union[Text, None] = None
|
|
||||||
headers: Dict
|
headers: Dict
|
||||||
|
cookies: Cookies
|
||||||
|
encoding: Union[Text, None] = None
|
||||||
content_type: Text
|
content_type: Text
|
||||||
body: Union[Text, bytes, Dict]
|
body: Union[Text, bytes, Dict]
|
||||||
|
|
||||||
@@ -147,8 +148,9 @@ class StepData(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class TestCaseSummary(BaseModel):
|
class TestCaseSummary(BaseModel):
|
||||||
name: Text = ""
|
name: Text
|
||||||
success: bool = False
|
success: bool
|
||||||
|
case_id: Text
|
||||||
time: TestCaseTime
|
time: TestCaseTime
|
||||||
in_out: TestCaseInOut = {}
|
in_out: TestCaseInOut = {}
|
||||||
log: Text = ""
|
log: Text = ""
|
||||||
|
|||||||
36
poetry.lock
generated
36
poetry.lock
generated
@@ -12,6 +12,32 @@ version = "0.2.2"
|
|||||||
python = "<3.7"
|
python = "<3.7"
|
||||||
version = "2.4"
|
version = "2.4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Allure pytest integration"
|
||||||
|
name = "allure-pytest"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "2.8.15"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
allure-python-commons = "2.8.15"
|
||||||
|
pytest = ">=4.5.0"
|
||||||
|
six = ">=1.9.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Common module for integrate allure with python-based frameworks"
|
||||||
|
name = "allure-python-commons"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "2.8.15"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
attrs = ">=16.0.0"
|
||||||
|
pluggy = ">=0.4.0"
|
||||||
|
six = ">=1.9.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "main"
|
category = "main"
|
||||||
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||||
@@ -516,7 +542,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
|
|||||||
testing = ["jaraco.itertools", "func-timeout"]
|
testing = ["jaraco.itertools", "func-timeout"]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
content-hash = "be53fb0cd423bac9dda129a958a58026009a99a455081333d7af51c22a4df8cf"
|
content-hash = "67027f8f78c61b981f3c01613ded1da2a0256a28fb92f95dd2d642b3fd1b43a5"
|
||||||
python-versions = "^3.6"
|
python-versions = "^3.6"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
@@ -524,6 +550,14 @@ aiocontextvars = [
|
|||||||
{file = "aiocontextvars-0.2.2-py2.py3-none-any.whl", hash = "sha256:885daf8261818767d8f7cbd79f9d4482d118f024b6586ef6e67980236a27bfa3"},
|
{file = "aiocontextvars-0.2.2-py2.py3-none-any.whl", hash = "sha256:885daf8261818767d8f7cbd79f9d4482d118f024b6586ef6e67980236a27bfa3"},
|
||||||
{file = "aiocontextvars-0.2.2.tar.gz", hash = "sha256:f027372dc48641f683c559f247bd84962becaacdc9ba711d583c3871fb5652aa"},
|
{file = "aiocontextvars-0.2.2.tar.gz", hash = "sha256:f027372dc48641f683c559f247bd84962becaacdc9ba711d583c3871fb5652aa"},
|
||||||
]
|
]
|
||||||
|
allure-pytest = [
|
||||||
|
{file = "allure-pytest-2.8.15.tar.gz", hash = "sha256:27f9c75194e95ba069ee2d6d2a2615ed6c7e96617ff9a492ab3a74f3f4e64be2"},
|
||||||
|
{file = "allure_pytest-2.8.15-py3-none-any.whl", hash = "sha256:62512bbce3d39b27a8e7ffbfb24e08e99c43df29b4f345168dfc9692bfddef71"},
|
||||||
|
]
|
||||||
|
allure-python-commons = [
|
||||||
|
{file = "allure-python-commons-2.8.15.tar.gz", hash = "sha256:c4768e5e1350fe2eb6e1c9dac6158dcb82e23de80c83c4fc6d71765c207c1408"},
|
||||||
|
{file = "allure_python_commons-2.8.15-py3-none-any.whl", hash = "sha256:88ad53109b6fa57e6b721f4eab59116db6037e219bf54e1f196a222ba5e2dcfe"},
|
||||||
|
]
|
||||||
appdirs = [
|
appdirs = [
|
||||||
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
|
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
|
||||||
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
|
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "httprunner"
|
name = "httprunner"
|
||||||
version = "3.0.4"
|
version = "3.0.5"
|
||||||
description = "One-stop solution for HTTP(S) testing."
|
description = "One-stop solution for HTTP(S) testing."
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
@@ -39,6 +39,7 @@ loguru = "^0.4.1"
|
|||||||
jmespath = "^0.9.5"
|
jmespath = "^0.9.5"
|
||||||
black = "^19.10b0"
|
black = "^19.10b0"
|
||||||
pytest = "^5.4.2"
|
pytest = "^5.4.2"
|
||||||
|
allure-pytest = "^2.8.15"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
coverage = "^4.5.4"
|
coverage = "^4.5.4"
|
||||||
|
|||||||
Reference in New Issue
Block a user