mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-12 02:21:29 +08:00
record more info about request and response, and display in report
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
__title__ = 'HttpRunner'
|
||||
__description__ = 'One-stop solution for HTTP(S) testing.'
|
||||
__url__ = 'https://github.com/HttpRunner/HttpRunner'
|
||||
__version__ = '1.5.3'
|
||||
__version__ = '1.5.4'
|
||||
__author__ = 'debugtalk'
|
||||
__author_email__ = 'mail@debugtalk.com'
|
||||
__license__ = 'MIT'
|
||||
|
||||
@@ -55,17 +55,20 @@ class HttpSession(requests.Session):
|
||||
""" initialize meta_data, it will store detail data of request and response
|
||||
"""
|
||||
self.meta_data = {
|
||||
"url": "N/A",
|
||||
"method": "N/A",
|
||||
"request_time": "N/A",
|
||||
"request_headers": {},
|
||||
"request_body": "N/A",
|
||||
"status_code": "N/A",
|
||||
"response_headers": {},
|
||||
"response_body": "N/A",
|
||||
"content_size": "N/A",
|
||||
"response_time_ms": "N/A",
|
||||
"elapsed_ms": "N/A"
|
||||
"request": {
|
||||
"url": "N/A",
|
||||
"method": "N/A",
|
||||
"headers": {},
|
||||
"start_timestamp": None
|
||||
},
|
||||
"response": {
|
||||
"status_code": "N/A",
|
||||
"headers": {},
|
||||
"content_size": "N/A",
|
||||
"response_time_ms": "N/A",
|
||||
"elapsed_ms": "N/A",
|
||||
"content": None
|
||||
}
|
||||
}
|
||||
|
||||
def request(self, method, url, name=None, **kwargs):
|
||||
@@ -107,10 +110,17 @@ class HttpSession(requests.Session):
|
||||
:param cert: (optional)
|
||||
if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
|
||||
"""
|
||||
def log_print(request_response):
|
||||
msg = "\n================== {} details ==================\n".format(request_response)
|
||||
for key, value in self.meta_data[request_response].items():
|
||||
msg += "{:<16} : {}\n".format(key, value)
|
||||
logger.log_debug(msg)
|
||||
|
||||
# record original request info
|
||||
self.meta_data["method"] = method
|
||||
self.meta_data["url"] = url
|
||||
self.meta_data["request_time"] = time.time()
|
||||
self.meta_data["request"]["method"] = method
|
||||
self.meta_data["request"]["url"] = url
|
||||
self.meta_data["request"].update(kwargs)
|
||||
self.meta_data["request"]["start_timestamp"] = time.time()
|
||||
|
||||
# prepend url with hostname unless it's already an absolute URL
|
||||
url = self._build_url(url)
|
||||
@@ -119,35 +129,43 @@ class HttpSession(requests.Session):
|
||||
response = self._send_request_safe_mode(method, url, **kwargs)
|
||||
|
||||
# record the consumed time
|
||||
self.meta_data["response_time_ms"] = round((time.time() - self.meta_data["request_time"]) * 1000, 2)
|
||||
self.meta_data["elapsed_ms"] = response.elapsed.microseconds / 1000.0
|
||||
self.meta_data["response"]["response_time_ms"] = \
|
||||
round((time.time() - self.meta_data["request"]["start_timestamp"]) * 1000, 2)
|
||||
self.meta_data["response"]["elapsed_ms"] = response.elapsed.microseconds / 1000.0
|
||||
|
||||
# record actual request info
|
||||
self.meta_data["url"] = (response.history and response.history[0] or response).request.url
|
||||
self.meta_data["request_headers"] = response.request.headers
|
||||
self.meta_data["request_body"] = response.request.body
|
||||
self.meta_data["request"]["url"] = (response.history and response.history[0] or response).request.url
|
||||
self.meta_data["request"]["headers"] = response.request.headers
|
||||
self.meta_data["request"]["body"] = response.request.body
|
||||
|
||||
# log request details in debug mode
|
||||
log_print("request")
|
||||
|
||||
# record response info
|
||||
self.meta_data["status_code"] = response.status_code
|
||||
self.meta_data["response_headers"] = response.headers
|
||||
try:
|
||||
self.meta_data["response_body"] = response.json()
|
||||
except ValueError:
|
||||
self.meta_data["response_body"] = response.content
|
||||
self.meta_data["response"]["ok"] = response.ok
|
||||
self.meta_data["response"]["url"] = response.url
|
||||
self.meta_data["response"]["status_code"] = response.status_code
|
||||
self.meta_data["response"]["reason"] = response.reason
|
||||
self.meta_data["response"]["headers"] = response.headers
|
||||
self.meta_data["response"]["cookies"] = response.cookies or {}
|
||||
self.meta_data["response"]["encoding"] = response.encoding
|
||||
self.meta_data["response"]["content"] = response.content
|
||||
self.meta_data["response"]["text"] = response.text
|
||||
|
||||
# log response details in debug mode
|
||||
msg = "response details:\n"
|
||||
msg += "> status_code: {}\n".format(self.meta_data["status_code"])
|
||||
msg += "> headers: {}\n".format(self.meta_data["response_headers"])
|
||||
msg += "> body: {}".format(self.meta_data["response_body"])
|
||||
logger.log_debug(msg)
|
||||
try:
|
||||
self.meta_data["response"]["json"] = response.json()
|
||||
except ValueError:
|
||||
self.meta_data["response"]["json"] = None
|
||||
|
||||
# get the length of the content, but if the argument stream is set to True, we take
|
||||
# the size from the content-length header, in order to not trigger fetching of the body
|
||||
if kwargs.get("stream", False):
|
||||
self.meta_data["content_size"] = int(self.meta_data["response_headers"].get("content-length") or 0)
|
||||
self.meta_data["response"]["content_size"] = int(self.meta_data["response"]["headers"].get("content-length") or 0)
|
||||
else:
|
||||
self.meta_data["content_size"] = len(response.content or "")
|
||||
self.meta_data["response"]["content_size"] = len(response.content or "")
|
||||
|
||||
# log response details in debug mode
|
||||
log_print("response")
|
||||
|
||||
try:
|
||||
response.raise_for_status()
|
||||
@@ -156,9 +174,9 @@ class HttpSession(requests.Session):
|
||||
else:
|
||||
logger.log_info(
|
||||
"""status_code: {}, response_time(ms): {} ms, response_length: {} bytes""".format(
|
||||
self.meta_data["status_code"],
|
||||
self.meta_data["response_time_ms"],
|
||||
self.meta_data["content_size"]
|
||||
self.meta_data["response"]["status_code"],
|
||||
self.meta_data["response"]["response_time_ms"],
|
||||
self.meta_data["response"]["content_size"]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ def stringify_body(meta_data, request_or_response):
|
||||
resp_content_type = headers.get("Content-Type", "")
|
||||
try:
|
||||
if "image" in resp_content_type:
|
||||
meta_data["response_data_type"] = "image"
|
||||
meta_data["response"]["data_type"] = "image"
|
||||
body = "data:{};base64,{}".format(
|
||||
resp_content_type,
|
||||
b64encode(body).decode('utf-8')
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
<tr id="record_{{record_index}}">
|
||||
<th class="{{record.status}}" style="width:5em;">{{record.status}}</td>
|
||||
<td colspan="2">{{record.name}}</td>
|
||||
<td style="text-align:center;width:6em;">{{ record.meta_data.response_time_ms }} ms</td>
|
||||
<td style="text-align:center;width:6em;">{{ record.meta_data.response.response_time_ms }} ms</td>
|
||||
<td class="detail">
|
||||
|
||||
<a class="button" href="#popup_log_{{record_index}}">log</a>
|
||||
@@ -249,66 +249,51 @@
|
||||
<h3>Request:</h3>
|
||||
<div style="overflow: auto">
|
||||
<table>
|
||||
<tr>
|
||||
<th>url</th>
|
||||
<td>{{ record.meta_data.url }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>method</th>
|
||||
<td>{{ record.meta_data.method }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>headers</th>
|
||||
<td>
|
||||
{% for key, value in record.meta_data.request_headers.items() %}
|
||||
<div>
|
||||
<strong>{{ key }}</strong>: {{ value }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% if record.meta_data.method in ["POST", "PUT"] %}
|
||||
<tr>
|
||||
<th>body</th>
|
||||
<td>
|
||||
<pre>{{ record.meta_data.request_body }}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
{% for key, value in record.meta_data.request.items() %}
|
||||
<tr>
|
||||
<th>{{key}}</th>
|
||||
<td>
|
||||
{% if key == "headers" %}
|
||||
{% for header_key, header_value in record.meta_data.request.headers.items() %}
|
||||
<div>
|
||||
<strong>{{ header_key }}</strong>: {{ header_value }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{{value}}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h3>Response:</h3>
|
||||
<div style="overflow: auto">
|
||||
<table>
|
||||
<tr>
|
||||
<th>status_code</th>
|
||||
<td>
|
||||
{{ record.meta_data.status_code }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>headers</th>
|
||||
<td>
|
||||
{% for key, value in record.meta_data.response_headers.items() %}
|
||||
<div>
|
||||
<strong>{{ key }}</strong>: {{ value }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>body</th>
|
||||
<td>
|
||||
{% if record.meta_data.response_data_type == "image" %}
|
||||
<img src="{{ record.meta_data.response_body }}" />
|
||||
{% else %}
|
||||
<pre>{{ record.meta_data.response_body }}</pre>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{% for key, value in record.meta_data.response.items() %}
|
||||
<tr>
|
||||
<th>{{key}}</th>
|
||||
<td>
|
||||
{% if key == "headers" %}
|
||||
{% for header_key, header_value in record.meta_data.request.headers.items() %}
|
||||
<div>
|
||||
<strong>{{ header_key }}</strong>: {{ header_value }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% elif key == "data_type" %}
|
||||
{% if value == "image" %}
|
||||
<img src="{{ record.meta_data.response.body }}" />
|
||||
{% else %}
|
||||
<pre>{{ record.meta_data.response.body }}</pre>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{value}}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h3>Validators:</h3>
|
||||
@@ -344,15 +329,15 @@
|
||||
<table>
|
||||
<tr>
|
||||
<th>content_size(bytes)</th>
|
||||
<td>{{ record.meta_data.content_size }}</td>
|
||||
<td>{{ record.meta_data.response.content_size }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>response_time(ms)</th>
|
||||
<td>{{ record.meta_data.response_time_ms }}</td>
|
||||
<td>{{ record.meta_data.response.response_time_ms }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>elapsed(ms)</th>
|
||||
<td>{{ record.meta_data.elapsed_ms }}</td>
|
||||
<td>{{ record.meta_data.response.elapsed_ms }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -137,7 +137,7 @@ class TestHttpRunner(ApiServerUnittest):
|
||||
summary = runner.summary
|
||||
self.assertTrue(summary["success"])
|
||||
self.assertEqual(summary["stat"]["testsRun"], 1)
|
||||
self.assertEqual(summary["details"][0]["records"][0]["meta_data"]["response_body"]["data"], "abc")
|
||||
self.assertEqual(summary["details"][0]["records"][0]["meta_data"]["response"]["json"]["data"], "abc")
|
||||
|
||||
def test_html_report_repsonse_image(self):
|
||||
testset_path = "tests/httpbin/load_image.yml"
|
||||
|
||||
Reference in New Issue
Block a user