一、接口自动化测试框架
二、工程目录
三、Excel测试用例设计
四、基础数据base
封装post/get:runmethod.py
-
#!/usr/bin/env python3
-
# -*-coding:utf-8-*-
-
# __author__: hunter
-
import requests
-
import json
-
class RunMain:
-
def send_get(self, url, data):
-
res = requests.get(url=url, params=data).json()
-
# return res
-
return json.dumps(res, indent=2, sort_keys=False, ensure_ascii=False)
-
def send_post(self, url, data):
-
res = requests.post(url=url, data=json.dumps(data)).json()
-
# return res
-
return json.dumps(res, indent=2, sort_keys=False, ensure_ascii=False)
-
def run_main(self, url, method, data=None):
-
if method == 'POST':
-
res = self.send_post(url, data)
-
else:
-
res = self.send_get(url, data)
-
return res
HTMLTestrunner:测试报告
-
"""
-
A TestRunner for use with the Python unit testing framework. It
-
generates a HTML report to show the result at a glance.
-
The simplest way to use this is to invoke its main method. E.g.
-
import unittest
-
import HTMLTestRunner
-
... define your tests ...
-
if __name__ == '__main__':
-
HTMLTestRunner.main()
-
For more customization options, instantiates a HTMLTestRunner object.
-
HTMLTestRunner is a counterpart to unittest's TextTestRunner. E.g.
-
# output to a file
-
fp = file('my_report.html', 'wb')
-
runner = HTMLTestRunner.HTMLTestRunner(
-
stream=fp,
-
title='My unit test',
-
description='This demonstrates the report output by HTMLTestRunner.'
-
)
-
# Use an external stylesheet.
-
# See the Template_mixin class for more customizable options
-
runner.STYLESHEET_TMPL = '<link rel="stylesheet" href="my_stylesheet.css" type="text/css">'
-
# run the test
-
runner.run(my_test_suite)
-
------------------------------------------------------------------------
-
Copyright (c) 2004-2007, Wai Yip Tung
-
All rights reserved.
-
Redistribution and use in source and binary forms, with or without
-
modification, are permitted provided that the following conditions are
-
met:
-
* Redistributions of source code must retain the above copyright notice,
-
this list of conditions and the following disclaimer.
-
* Redistributions in binary form must reproduce the above copyright
-
notice, this list of conditions and the following disclaimer in the
-
documentation and/or other materials provided with the distribution.
-
* Neither the name Wai Yip Tung nor the names of its contributors may be
-
used to endorse or promote products derived from this software without
-
specific prior written permission.
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
-
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
"""
-
# URL: http://tungwaiyip.info/software/HTMLTestRunner.html
-
__author__ = "Wai Yip Tung"
-
__version__ = "0.8.2"
-
"""
-
Change History
-
Version 0.8.2
-
* Show output inline instead of popup window (Viorel Lupu).
-
Version in 0.8.1
-
* Validated XHTML (Wolfgang Borgert).
-
* Added description of test classes and test cases.
-
Version in 0.8.0
-
* Define Template_mixin class for customization.
-
* Workaround a IE 6 bug that it does not treat <script> block as CDATA.
-
Version in 0.7.1
-
* Back port to Python 2.3 (Frank Horowitz).
-
* Fix missing scroll bars in detail log (Podi).
-
"""
-
# TODO: color stderr
-
# TODO: simplify javascript using ,ore than 1 class in the class attribute?
-
import datetime
-
import io
-
import sys
-
import time
-
import unittest
-
from xml.sax import saxutils
-
# ------------------------------------------------------------------------
-
# The redirectors below are used to capture output during testing. Output
-
# sent to sys.stdout and sys.stderr are automatically captured. However
-
# in some cases sys.stdout is already cached before HTMLTestRunner is
-
# invoked (e.g. calling logging.basicConfig). In order to capture those
-
# output, use the redirectors for the cached stream.
-
#
-
# e.g.
-
# >>> logging.basicConfig(stream=HTMLTestRunner.stdout_redirector)
-
# >>>
-
class OutputRedirector(object):
-
""" Wrapper to redirect stdout or stderr """
-
def __init__(self, fp):
-
self.fp = fp
-
def write(self, s):
-
self.fp.write(s)
-
def writelines(self, lines):
-
self.fp.writelines(lines)
-
def flush(self):
-
self.fp.flush()
-
stdout_redirector = OutputRedirector(sys.stdout)
-
stderr_redirector = OutputRedirector(sys.stderr)
-
# ----------------------------------------------------------------------
-
# Template
-
class Template_mixin(object):
-
"""
-
Define a HTML template for report customerization and generation.
-
Overall structure of an HTML report
-
HTML
-
+------------------------+
-
|<html> |
-
| <head> |
-
| |
-
| STYLESHEET |
-
| +----------------+ |
-
| | | |
-
| +----------------+ |
-
| |
-
| </head> |
-
| |
-
| <body> |
-
| |
-
| HEADING |
-
| +----------------+ |
-
| | | |
-
| +----------------+ |
-
| |
-
| REPORT |
-
| +----------------+ |
-
| | | |
-
| +----------------+ |
-
| |
-
| ENDING |
-
| +----------------+ |
-
| | | |
-
| +----------------+ |
-
| |
-
| </body> |
-
|</html> |
-
+------------------------+
-
"""
-
STATUS = {
-
0: 'pass',
-
1: 'fail',
-
2: 'error',
-
}
-
DEFAULT_TITLE = 'Unit Test Report'
-
DEFAULT_DESCRIPTION = ''
-
# ------------------------------------------------------------------------
-
# HTML Template
-
HTML_TMPL = r"""<?xml version="1.0" encoding="UTF-8"?>
-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
<html xmlns="http://www.w3.org/1999/xhtml">
-
<head>
-
<title>%(title)s</title>
-
<meta name="generator" content="%(generator)s"/>
-
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
-
%(stylesheet)s
-
</head>
-
<body>
-
<script language="javascript" type="text/javascript"><!--
-
output_list = Array();
-
/* level - 0:Summary; 1:Failed; 2:All */
-
function showCase(level) {
-
trs = document.getElementsByTagName("tr");
-
for (var i = 0; i < trs.length; i++) {
-
tr = trs[i];
-
id = tr.id;
-
if (id.substr(0,2) == 'ft') {
-
if (level < 1) {
-
tr.className = 'hiddenRow';
-
}
-
else {
-
tr.className = '';
-
}
-
}
-
if (id.substr(0,2) == 'pt') {
-
if (level > 1) {
-
tr.className = '';
-
}
-
else {
-
tr.className = 'hiddenRow';
-
}
-
}
-
}
-
}
-
function showClassDetail(cid, count) {
-
var id_list = Array(count);
-
var toHide = 1;
-
for (var i = 0; i < count; i++) {
-
tid0 = 't' + cid.substr(1) + '.' + (i+1);
-
tid = 'f' + tid0;
-
tr = document.getElementById(tid);
-
if (!tr) {
-
tid = 'p' + tid0;
-
tr = document.getElementById(tid);
-
}
-
id_list[i] = tid;
-
if (tr.className) {
-
toHide = 0;
-
}
-
}
-
for (var i = 0; i < count; i++) {
-
tid = id_list[i];
-
if (toHide) {
-
document.getElementById('div_'+tid).style.display = 'none'
-
document.getElementById(tid).className = 'hiddenRow';
-
}
-
else {
-
document.getElementById(tid).className = '';
-
}
-
}
-
}
-
function showTestDetail(div_id){
-
var details_div = document.getElementById(div_id)
-
var displayState = details_div.style.display
-
// alert(displayState)
-
if (displayState != 'block' ) {
-
displayState = 'block'
-
details_div.style.display = 'block'
-
}
-
else {
-
details_div.style.display = 'none'
-
}
-
}
-
function html_escape(s) {
-
s = s.replace(/&/g,'&');
-
s = s.replace(/</g,'<');
-
s = s.replace(/>/g,'>');
-
return s;
-
}
-
/* obsoleted by detail in <div>
-
function showOutput(id, name) {
-
var w = window.open("", //url
-
name,
-
"resizable,scrollbars,status,width=800,height=450");
-
d = w.document;
-
d.write("<pre>");
-
d.write(html_escape(output_list[id]));
-
d.write("\n");
-
d.write("<a href='javascript:window.close()'>close</a>\n");
-
d.write("</pre>\n");
-
d.close();
-
}
-
*/
-
--></script>
-
%(heading)s
-
%(report)s
-
%(ending)s
-
</body>
-
</html>
-
"""
-
# variables: (title, generator, stylesheet, heading, report, ending)
-
# ------------------------------------------------------------------------
-
# Stylesheet
-
#
-
# alternatively use a <link> for external style sheet, e.g.
-
# <link rel="stylesheet" href="$url" type="text/css">
-
STYLESHEET_TMPL = """
-
<style type="text/css" media="screen">
-
body { font-family: verdana, arial, helvetica, sans-serif; font-size: 80%; }
-
table { font-size: 100%; }
-
pre { }
-
/* -- heading ---------------------------------------------------------------------- */
-
h1 {
-
font-size: 16pt;
-
color: gray;
-
}
-
.heading {
-
margin-top: 0ex;
-
margin-bottom: 1ex;
-
}
-
.heading .attribute {
-
margin-top: 1ex;
-
margin-bottom: 0;
-
}
-
.heading .description {
-
margin-top: 4ex;
-
margin-bottom: 6ex;
-
}
-
/* -- css div popup ------------------------------------------------------------------------ */
-
a.popup_link {
-
}
-
a.popup_link:hover {
-
color: red;
-
}
-
.popup_window {
-
display: none;
-
position: relative;
-
left: 0px;
-
top: 0px;
-
/*border: solid #627173 1px; */
-
padding: 10px;
-
background-color: #E6E6D6;
-
font-family: "Lucida Console", "Courier New", Courier, monospace;
-
text-align: left;
-
font-size: 8pt;
-
width: 500px;
-
}
-
}
-
/* -- report ------------------------------------------------------------------------ */
-
#show_detail_line {
-
margin-top: 3ex;
-
margin-bottom: 1ex;
-
}
-
#result_table {
-
width: 80%;
-
border-collapse: collapse;
-
border: 1px solid #777;
-
}
-
#header_row {
-
font-weight: bold;
-
color: white;
-
background-color: #777;
-
}
-
#result_table td {
-
border: 1px solid #777;
-
padding: 2px;
-
}
-
#total_row { font-weight: bold; }
-
.passClass { background-color: #6c6; }
-
.failClass { background-color: #c60; }
-
.errorClass { background-color: #c00; }
-
.passCase { color: #6c6; }
-
.failCase { color: #c60; font-weight: bold; }
-
.errorCase { color: #c00; font-weight: bold; }
-
.hiddenRow { display: none; }
-
.testcase { margin-left: 2em; }
-
/* -- ending ---------------------------------------------------------------------- */
-
#ending {
-
}
-
</style>
-
"""
-
# ------------------------------------------------------------------------
-
# Heading
-
#
-
HEADING_TMPL = """<div class='heading'>
-
<h1>%(title)s</h1>
-
%(parameters)s
-
<p class='description'>%(description)s</p>
-
</div>
-
""" # variables: (title, parameters, description)
-
HEADING_ATTRIBUTE_TMPL = """<p class='attribute'><strong>%(name)s:</strong> %(value)s</p>
-
""" # variables: (name, value)
-
# ------------------------------------------------------------------------
-
# Report
-
#
-
REPORT_TMPL = """
-
<p id='show_detail_line'>Show
-
<a href='javascript:showCase(0)'>Summary</a>
-
<a href='javascript:showCase(1)'>Failed</a>
-
<a href='javascript:showCase(2)'>All</a>
-
</p>
-
<table id='result_table'>
-
<colgroup>
-
<col align='left' />
-
<col align='right' />
-
<col align='right' />
-
<col align='right' />
-
<col align='right' />
-
<col align='right' />
-
</colgroup>
-
<tr id='header_row'>
-
<td>Test Group/Test case</td>
-
<td>Count</td>
-
<td>Pass</td>
-
<td>Fail</td>
-
<td>Error</td>
-
<td>View</td>
-
</tr>
-
%(test_list)s
-
<tr id='total_row'>
-
<td>Total</td>
-
<td>%(count)s</td>
-
<td>%(Pass)s</td>
-
<td>%(fail)s</td>
-
<td>%(error)s</td>
-
<td> </td>
-
</tr>
-
</table>
-
""" # variables: (test_list, count, Pass, fail, error)
-
REPORT_CLASS_TMPL = r"""
-
<tr class='%(style)s'>
-
<td>%(desc)s</td>
-
<td>%(count)s</td>
-
<td>%(Pass)s</td>
-
<td>%(fail)s</td>
-
<td>%(error)s</td>
-
<td><a href="javascript:showClassDetail('%(cid)s',%(count)s)">Detail</a></td>
-
</tr>
-
""" # variables: (style, desc, count, Pass, fail, error, cid)
-
REPORT_TEST_WITH_OUTPUT_TMPL = r"""
-
<tr id='%(tid)s' class='%(Class)s'>
-
<td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
-
<td colspan='5' align='center'>
-
<!--css div popup start-->
-
<a class="popup_link" onfocus='this.blur();' href="javascript:showTestDetail('div_%(tid)s')" >
-
%(status)s</a>
-
<div id='div_%(tid)s' class="popup_window">
-
<div style='text-align: right; color:red;cursor:pointer'>
-
<a onfocus='this.blur();' onclick="document.getElementById('div_%(tid)s').style.display = 'none' " >
-
[x]</a>
-
</div>
-
<pre>
-
%(script)s
-
</pre>
-
</div>
-
<!--css div popup end-->
-
</td>
-
</tr>
-
""" # variables: (tid, Class, style, desc, status)
-
REPORT_TEST_NO_OUTPUT_TMPL = r"""
-
<tr id='%(tid)s' class='%(Class)s'>
-
<td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
-
<td colspan='5' align='center'>%(status)s</td>
-
</tr>
-
""" # variables: (tid, Class, style, desc, status)
-
REPORT_TEST_OUTPUT_TMPL = r"""
-
%(id)s: %(output)s
-
""" # variables: (id, output)
-
# ------------------------------------------------------------------------
-
# ENDING
-
#
-
ENDING_TMPL = """<div id='ending'> </div>"""
-
# -------------------- The end of the Template class -------------------
-
TestResult = unittest.TestResult
-
class _TestResult(TestResult):
-
# note: _TestResult is a pure representation of results.
-
# It lacks the output and reporting ability compares to unittest._TextTestResult.
-
def __init__(self, verbosity=1):
-
TestResult.__init__(self)
-
self.stdout0 = None
-
self.stderr0 = None
-
self.success_count = 0
-
self.failure_count = 0
-
self.error_count = 0
-
self.verbosity = verbosity
-
# result is a list of result in 4 tuple
-
# (
-
# result code (0: success; 1: fail; 2: error),
-
# TestCase object,
-
# Test output (byte string),
-
# stack trace,
-
# )
-
self.result = []
-
def startTest(self, test):
-
TestResult.startTest(self, test)
-
# just one buffer for both stdout and stderr
-
self.outputBuffer = io.BytesIO()
-
stdout_redirector.fp = self.outputBuffer
-
stderr_redirector.fp = self.outputBuffer
-
self.stdout0 = sys.stdout
-
self.stderr0 = sys.stderr
-
sys.stdout = stdout_redirector
-
sys.stderr = stderr_redirector
-
def complete_output(self):
-
"""
-
Disconnect output redirection and return buffer.
-
Safe to call multiple times.
-
"""
-
if self.stdout0:
-
sys.stdout = self.stdout0
-
sys.stderr = self.stderr0
-
self.stdout0 = None
-
self.stderr0 = None
-
return self.outputBuffer.getvalue()
-
def stopTest(self, test):
-
# Usually one of addSuccess, addError or addFailure would have been called.
-
# But there are some path in unittest that would bypass this.
-
# We must disconnect stdout in stopTest(), which is guaranteed to be called.
-
self.complete_output()
-
def addSuccess(self, test):
-
self.success_count += 1
-
TestResult.addSuccess(self, test)
-
output = self.complete_output()
-
self.result.append((0, test, output, ''))
-
if self.verbosity > 1:
-
sys.stderr.write('ok ')
-
sys.stderr.write(str(test))
-
sys.stderr.write('\n')
-
else:
-
sys.stderr.write('.')
-
def addError(self, test, err):
-
self.error_count += 1
-
TestResult.addError(self, test, err)
-
_, _exc_str = self.errors[-1]
-
output = self.complete_output()
-
self.result.append((2, test, output, _exc_str))
-
if self.verbosity > 1:
-
sys.stderr.write('E ')
-
sys.stderr.write(str(test))
-
sys.stderr.write('\n')
-
else:
-
sys.stderr.write('E')
-
def addFailure(self, test, err):
-
self.failure_count += 1
-
TestResult.addFailure(self, test, err)
-
_, _exc_str = self.failures[-1]
-
output = self.complete_output()
-
self.result.append((1, test, output, _exc_str))
-
if self.verbosity > 1:
-
sys.stderr.write('F ')
-
sys.stderr.write(str(test))
-
sys.stderr.write('\n')
-
else:
-
sys.stderr.write('F')
-
class HTMLTestRunner(Template_mixin):
-
"""
-
"""
-
def __init__(self, stream=sys.stdout, verbosity=1, title=None, description=None):
-
self.stream = stream
-
self.verbosity = verbosity
-
if title is None:
-
self.title = self.DEFAULT_TITLE
-
else:
-
self.title = title
-
if description is None:
-
self.description = self.DEFAULT_DESCRIPTION
-
else:
-
self.description = description
-
self.startTime = datetime.datetime.now()
-
def run(self, test):
-
"Run the given test case or test suite."
-
result = _TestResult(self.verbosity)
-
test(result)
-
self.stopTime = datetime.datetime.now()
-
self.generateReport(test, result)
-
print(sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime))
-
return result
-
def sortResult(self, result_list):
-
# unittest does not seems to run in any particular order.
-
# Here at least we want to group them together by class.
-
rmap = {}
-
classes = []
-
for n,t,o,e in result_list:
-
cls = t.__class__
-
if not cls in rmap:
-
rmap[cls] = []
-
classes.append(cls)
-
rmap[cls].append((n,t,o,e))
-
r = [(cls, rmap[cls]) for cls in classes]
-
return r
-
def getReportAttributes(self, result):
-
"""
-
Return report attributes as a list of (name, value).
-
Override this to add custom attributes.
-
"""
-
startTime = str(self.startTime)[:19]
-
duration = str(self.stopTime - self.startTime)
-
status = []
-
if result.success_count: status.append('Pass %s' % result.success_count)
-
if result.failure_count: status.append('Failure %s' % result.failure_count)
-
if result.error_count: status.append('Error %s' % result.error_count )
-
if status:
-
status = ' '.join(status)
-
else:
-
status = 'none'
-
return [
-
('Start Time', startTime),
-
('Duration', duration),
-
('Status', status),
-
]
-
def generateReport(self, test, result):
-
report_attrs = self.getReportAttributes(result)
-
generator = 'HTMLTestRunner %s' % __version__
-
stylesheet = self._generate_stylesheet()
-
heading = self._generate_heading(report_attrs)
-
report = self._generate_report(result)
-
ending = self._generate_ending()
-
output = self.HTML_TMPL % dict(
-
title = saxutils.escape(self.title),
-
generator = generator,
-
stylesheet = stylesheet,
-
heading = heading,
-
report = report,
-
ending = ending,
-
)
-
self.stream.write(output.encode('utf8'))
-
def _generate_stylesheet(self):
-
return self.STYLESHEET_TMPL
-
def _generate_heading(self, report_attrs):
-
a_lines = []
-
for name, value in report_attrs:
-
line = self.HEADING_ATTRIBUTE_TMPL % dict(
-
name = saxutils.escape(name),
-
value = saxutils.escape(value),
-
)
-
a_lines.append(line)
-
heading = self.HEADING_TMPL % dict(
-
title = saxutils.escape(self.title),
-
parameters = ''.join(a_lines),
-
description = saxutils.escape(self.description),
-
)
-
return heading
-
def _generate_report(self, result):
-
rows = []
-
sortedResult = self.sortResult(result.result)
-
for cid, (cls, cls_results) in enumerate(sortedResult):
-
# subtotal for a class
-
np = nf = ne = 0
-
for n,t,o,e in cls_results:
-
if n == 0: np += 1
-
elif n == 1: nf += 1
-
else: ne += 1
-
# format class description
-
if cls.__module__ == "__main__":
-
name = cls.__name__
-
else:
-
name = "%s.%s" % (cls.__module__, cls.__name__)
-
doc = cls.__doc__ and cls.__doc__.split("\n")[0] or ""
-
desc = doc and '%s: %s' % (name, doc) or name
-
row = self.REPORT_CLASS_TMPL % dict(
-
style = ne > 0 and 'errorClass' or nf > 0 and 'failClass' or 'passClass',
-
desc = desc,
-
count = np+nf+ne,
-
Pass = np,
-
fail = nf,
-
error = ne,
-
cid = 'c%s' % (cid+1),
-
)
-
rows.append(row)
-
for tid, (n,t,o,e) in enumerate(cls_results):
-
self._generate_report_test(rows, cid, tid, n, t, o, e)
-
report = self.REPORT_TMPL % dict(
-
test_list = ''.join(rows),
-
count = str(result.success_count+result.failure_count+result.error_count),
-
Pass = str(result.success_count),
-
fail = str(result.failure_count),
-
error = str(result.error_count),
-
)
-
return report
-
def _generate_report_test(self, rows, cid, tid, n, t, o, e):
-
# e.g. 'pt1.1', 'ft1.1', etc
-
has_output = bool(o or e)
-
tid = (n == 0 and 'p' or 'f') + 't%s.%s' % (cid+1,tid+1)
-
name = t.id().split('.')[-1]
-
doc = t.shortDescription() or ""
-
desc = doc and ('%s: %s' % (name, doc)) or name
-
tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL
-
# o and e should be byte string because they are collected from stdout and stderr?
-
if isinstance(o,str):
-
# TODO: some problem with 'string_escape': it escape \n and mess up formating
-
# uo = unicode(o.encode('string_escape'))
-
uo = o.decode('latin-1')
-
else:
-
uo = o
-
if isinstance(e,str):
-
# TODO: some problem with 'string_escape': it escape \n and mess up formating
-
# ue = unicode(e.encode('string_escape'))
-
ue = e
-
else:
-
ue = e
-
script = self.REPORT_TEST_OUTPUT_TMPL % dict(
-
id = tid,
-
output = saxutils.escape(str(uo)+ue),
-
)
-
row = tmpl % dict(
-
tid = tid,
-
Class = (n == 0 and 'hiddenRow' or 'none'),
-
style = n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'none'),
-
desc = desc,
-
script = script,
-
status = self.STATUS[n],
-
)
-
rows.append(row)
-
if not has_output:
-
return
-
def _generate_ending(self):
-
return self.ENDING_TMPL
-
##############################################################################
-
# Facilities for running tests from the command line
-
##############################################################################
-
# Note: Reuse unittest.TestProgram to launch test. In the future we may
-
# build our own launcher to support more specific command line
-
# parameters like test title, CSS, etc.
-
class TestProgram(unittest.TestProgram):
-
"""
-
A variation of the unittest.TestProgram. Please refer to the base
-
class for command line parameters.
-
"""
-
def runTests(self):
-
# Pick HTMLTestRunner as the default test runner.
-
# base class's testRunner parameter is not useful because it means
-
# we have to instantiate HTMLTestRunner before we know self.verbosity.
-
if self.testRunner is None:
-
self.testRunner = HTMLTestRunner(verbosity=self.verbosity)
-
unittest.TestProgram.runTests(self)
-
main = TestProgram
-
##############################################################################
-
# Executing this module from the command line
-
##############################################################################
-
if __name__ == "__main__":
-
main(module=None)
五、data操作Excel的读写、日志
handle_excel.py:封装Excel的读写
-
#!/usr/bin/env python3
-
# -*-coding:utf-8-*-
-
# __author__: hunter
-
import xlrd
-
from xlutils.copy import copy
-
class HandleExcel:
-
"""封装操作Excel的方法"""
-
def __init__(self, file='D:/hunter_/interfaceTest/hunter_interface/case/demo2.xlsx', sheet_id=0):
-
self.file = file
-
self.sheet_id = sheet_id
-
self.data = self.get_data()
-
# 为了创建一个实例时就获得Excel的sheet对象,可以在构造器中调用get_data()
-
# 因为类在实例化时就会自动调用构造器,这样创建一个实例时就会自动获得sheet对象了
-
# 获取某一页sheet对象
-
def get_data(self):
-
data = xlrd.open_workbook(self.file)
-
sheet = data.sheet_by_index(self.sheet_id)
-
return sheet
-
# 获取Excel数据行数
-
def get_rows(self):
-
rows = self.data.nrows
-
return rows
-
# 获取某个单元格写入数据
-
def get_value(self, row, col):
-
value = self.data.cell_value(row, col)
-
return value
-
# 向某个单元格写入数据
-
def write_value(self, row, col, value):
-
data = xlrd.open_workbook(self.file) # 打开文件
-
data_copy = copy(data) # 复制源文件
-
sheet = data_copy.get_sheet(0) # 取得复制文件的sheet对象
-
sheet.write(row, col, value) # 在某一单元格写入value
-
data_copy.save(self.file) # 保存文件
-
def get_caseNmber():
-
caseNmber = 0
-
return caseNmber
-
def get_caseType():
-
caseType = 1
-
return caseType
-
def get_caseName():
-
caseName = 2
-
return caseName
-
def get_priority():
-
priority = 3
-
return priority
-
def get_url():
-
url = 4
-
return url
-
def get_mothod():
-
mothod = 5
-
return mothod
-
def get_header():
-
header = 6
-
return header
-
def get_purpose():
-
purpose = 7
-
return purpose
-
def get_params():
-
params = 8
-
return params
-
def get_expectvalue():
-
expectvalue = 9
-
return expectvalue
-
def get_actualvalue():
-
actualvalue = 10
-
return actualvalue
-
def get_resultvalue():
-
resultvalue = 11
-
return resultvalue
logger:封装日志
-
#!/usr/bin/env python3
-
# -*-coding:utf-8-*-
-
# __author__: hunter
-
import logging
-
import os
-
import time
-
class Logger:
-
def __init__(self, loggername):
-
# 创建一个logger
-
self.logger = logging.getLogger(loggername)
-
print(self.logger)
-
self.logger.setLevel(logging.DEBUG)
-
# 创建一个handler,用于写入文件
-
rq = time.strftime('%Y%m%d', time.localtime(time.time()))
-
log_path = os.path.dirname(os.path.abspath('.')) + '/logs/' # 指定文件输出路径,注意logs是一个文件夹,
-
logname = log_path + rq + 'test.log' # 指定输出的日志文件名
-
fh = logging.FileHandler(logname, encoding='utf-8') # 指定utf-8格式编码,避免输出的日志文本乱码
-
print(fh)
-
fh.setLevel(logging.DEBUG)
-
# 创建一个handler,用于将日志输出到控制台
-
ch = logging.StreamHandler()
-
ch.setLevel(logging.DEBUG)
-
# 定义handler的输出格式
-
formatter = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s-%(message)s')
-
fh.setFormatter(formatter)
-
ch.setFormatter(formatter)
-
# 给logger添加handler
-
self.logger.addHandler(fh)
-
self.logger.addHandler(ch)
-
def get_log(self):
-
"""定义一个函数,回调logger实例"""
-
return self.logger
六、日志
20190928test.log
七、main主函数
run_test.py
-
#!/usr/bin/env python3
-
# -*-coding:utf-8-*-
-
# __author__: hunter
-
from conn.run_demo import RunMain
-
from hunter_interface.data.handle_excel import *
-
from hunter_interface.data.logger import Logger
-
import json
-
from hunter_interface.base.runmethod import RunMain
-
class RunTestCase:
-
def __init__(self):
-
self.Runmain = RunMain()
-
self.data = HandleExcel()
-
self.logger = Logger(__name__)
-
def go_run(self):
-
rows_count = self.data.get_rows() # 获取Excel行数
-
for i in range(1, rows_count):
-
url = self.data.get_value(i, get_url()) # 循环获取URL的值
-
method = self.data.get_value(i, get_mothod()) # 循环获取method的值
-
print(self.data.get_value(i, get_params()))
-
data = json.loads(self.data.get_value(i, get_params()))
-
expect = self.data.get_value(i, get_expectvalue())
-
is_run = self.data.get_value(i, get_priority())
-
if is_run == 'high':
-
res = self.Runmain.run_main(url, method, data)
-
self.logger.get_log().debug('第' + str(i) + '个接口的返回结果为:%s', res) # 日志:输出接口响应内容
-
self.data.write_value(i, get_actualvalue(), res) # 将实际结果写入Excel中
-
if expect in res: # res返回的内容是否包含expect,是否与期望一致
-
print((expect))
-
print(type(expect))
-
print((res))
-
print(type(res))
-
print('测试通过')
-
self.logger.get_log().error('第' + str(i) + '接口测试通过')
-
self.data.write_value(i, get_resultvalue(), 'pass') # 调用写入数据方法,将结果写进Excel
-
else:
-
# print("测试失败")
-
self.logger.get_log().info('第' + str(i) + '接口测试失败')
-
self.data.write_value(i, get_resultvalue(), 'fail')
-
if __name__ == '__main__':
-
run = RunTestCase()
-
run.go_run()
八、测试报告report
最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】