前言:

首先我们先明确一个概念,什么叫接口、什么叫接口测试?

接口的全称叫【Application Programming Interface 又叫API】,是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换,传递和控制管理过程,以及系统间的相互逻辑依赖关系等。

(本章不会讲POSTMan、Jmeter等工具,直接入直路,工具毕竟是有依赖性)

一. 前期准备

1、准备工具:

本文版权归作者和博客园共有,原创作者:http://www.cnblogs.com/BenLam,未经作者同意必须在文章页面给出原文连接。

1、Python3.7 + notepad (Windows自带的文本文档工具)|(Linux配合vi编辑也可以)

2、Request库:下载地址 或通过Pip命令安装lib库:

pip install requests

  3、urllib、Unittest

  4、HTMLTestRunner获取方法【打开下面折叠代码,另存为HTMLTestRunner_Py3.Py文件】

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @file : HTMLTestRunner_Py3.x.py
# @Date : 2018-06-02 14:14:46
# @Author : Destroyers (https://github.com/lguobin)
# @Link : https://github.com/lguobin
# @Version : $1.0$ """
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.1" # lguobin change Python 3.x """
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.StringIO()
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)
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')
uo = e
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.decode('latin-1')
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)

HTMLTestRunner Code

2、示例接口说明:

演示接口:豆瓣电影搜索

文档说明:https://developers.douban.com/wiki/?title=movie_v2#search

api请求地址:https://api.douban.com/v2/movie/search?

1、按片名搜索:api请求地址 + q=钢铁侠

2、按类型搜索:api请求地址 + tag=喜剧

说明:在实际工作中接口说明开发会提供交到我们手上的,不用担心。

3、接口踩点:

1、拿到 api 先别着急测试,通过手工点点能否正常使用

2、编写对应的测试用例,例如上边测试按电影的片名和类型搜索:(演示)

testdemo1: https://api.douban.com/v2/movie/search?q=钢铁侠
testdemo2: https://api.douban.com/v2/movie/search?q=喜剧
testdemo3: https://api.douban.com/v2/movie/search?q=恐龙恐怖片
testdemo4: https://api.douban.com/v2/movie/search?q=

二. 接口调用(我会通过使用两个Python库来实现与接口通讯)

1、urllib发起请求:

本文版权归作者和博客园共有,原创作者:http://www.cnblogs.com/BenLam,未经作者同意必须在文章页面给出原文连接。

import urllib.request
params = "TomCruise" # 汤姆·克鲁斯的电影
url = "https://api.douban.com/v2/movie/search?"
html = urllib.request.urlopen(url + params) # 通过urllib发起请求
html = html.read().decode("utf-8")
print(html)

2、Requests发起请求:

import requests
params = "TomCruise" # 汤姆·克鲁斯的电影
url = "https://api.douban.com/v2/movie/search?"
req = requests.get(url) # 通过requests 发起请求
print(req)

打印结果:

{
"count": 20,
"start": 0,
"total": 40,
"subjects": [{
"rating": {
"max": 10,
"average": 7.7,
"stars": "40",
"min": 0
},
"genres": ["剧情", "悬疑", "惊悚"],
"title": "大开眼戒",
"casts": [{
"alt": "https:\/\/movie.douban.com\/celebrity\/1054435\/",
"avatars": {
"small": "https://img1.doubanio.com\/view\/celebrity\/s_ratio_celebrity\/public\/p567.jpg",
"large": "https://img1.doubanio.com\/view\/celebrity\/s_ratio_celebrity\/public\/p567.jpg",
"medium": "https://img1.doubanio.com\/view\/celebrity\/s_ratio_celebrity\/public\/p567.jpg"
},
"name": "汤姆·克鲁斯",
"id": "1054435"
.......... 省略很多东西 ...............
"title": "搜索 \"TomCruise\" 的结果"
}
json内容太长了,浓缩了重点

这样就完成了我们第一次请求api内容。

三. 结果校验

1、Python自身特性断言:

本文版权归作者和博客园共有,原创作者:http://www.cnblogs.com/BenLam,未经作者同意必须在文章页面给出原文连接。

通过Requests请求,用Python IF 判断 HTTP 状态码(只有验证码是200就通过)

import requests
actor_name = "q=TomCruise" # 汤姆·克鲁斯的电影
url = "https://api.douban.com/v2/movie/search?"
req = requests.get(url + actor_name) # 通过requests 发起请求
if req.status_code == 200:
# req.status_code 就是HTTP的状态码
print("测试通过,请求已成功,请求所希望的响应头或数据体将随此响应返回")
elif req.status_code == 301:
# 有些重定向的301 可以用 elif 再判断
print("重定向过,被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一")
elif req.status_code == 500:
print("服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。")
elif req.status_code == 404:
print("请求失败,请求所希望得到的资源未被在服务器上发现。")
else:
print("请求出现意外,未找到合适的 HTTP Status_code!") # 好处:通过Python自身的特性来判断返回的状态码是否正确
# 坏处:判断过于简单,无法精准检查接口

用Python IF 判断加强版

import requests,json
actor_name = "q=TomCruise" # 演员名
url = "https://api.douban.com/v2/movie/search?"
try:
req = requests.get(url + actor_name) # 通过requests 发起请求
req = json.dumps(req.json(), ensure_ascii=False, indent=4)
except requests.RequestException as e:
raise
name = "汤姆·克鲁斯"
if name in req: # 判断返回的数据是否包括我们搜索的条件,这里我们搜索是“汤姆克鲁斯”
print("通过测试")
else:
print("测试不通过")

2.2、Unittest断言:

使用unittest进行判断测试结果是否包含我们想要的信息

import requests,json
import unittest class demo(unittest.TestCase):
def setUp(self):
# 初始化信息
self.url = "https://api.douban.com/v2/movie/search?"
self.actor_name = "q=TomCruise"
self.style_tag = "tag=爱情"
self.name = "汤姆·克鲁斯"
self.action = "动作" def test_actor(self):
# 执行测试
req = requests.get(self.url + self.actor_name) # 通过requests 发起请求
req = json.dumps(req.json(), ensure_ascii=False, indent=4)
self.assertIn(self.name, req, msg=None) # 检查有没有 "汤姆·克鲁斯"这个演员 def test_style_tag(self):
# 执行测试
req = requests.get(self.url + self.actor_name) # 通过requests 发起请求
req = json.dumps(req.json(), ensure_ascii=False, indent=4)
self.assertIn(self.action, req, msg=None) # 检查有没有 "动作片" if __name__ == '__main__':
unittest.main()

这是通过测试的运行结果:

..
----------------------------------------------------------------------
Ran 2 tests in 1.610s OK
[Run in 1.9s]

如果测试结果不通过显示F (如下):

import unittest

class demo(unittest.TestCase):
def test_Error(self):
a = ""
b = ""
self.assertEqual(a,b) # 检查 a 和 b 是否相同 if __name__ == '__main__':
unittest.main() # ==============================
# 测试结果
# ==============================
F
======================================================================
FAIL: test_Error (__main__.demo)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\1\demo.py", line 45, in test_Error
self.assertEqual(a,b) # 检查 a 和 b 是否相同
AssertionError: '' != ''
- 1
+ 2 ----------------------------------------------------------------------
Ran 1 test in 0.000s FAILED (failures=1)
[Run in 0.3s with exit code 1]

四. 报告生成

本文版权归作者和博客园共有,原创作者:http://www.cnblogs.com/BenLam,未经作者同意必须在文章页面给出原文连接。

通过HTMLTestRunner快速生成:

import unittest
import HTMLTestRunner
import time
class Test(unittest.TestCase):
def test_case1(self):
# 填写你的测试用例 if __name__ == '__main__':
# 获取当前时间
now = time.strftime("%Y-%m-%d-%H_%M_%S", time.localtime(time.time()))
# html存放文件路径
Report_path = (Report_path, "Report_"+now+".html")
# 打开一个文件,将result写入此file中
file = open(Report_path, "wb")
runner = HTMLTestRunner.HTMLTestRunner(stream=file, title=u'接口测试报告:', description=u'用例执行情况:')
# 这里填写你的测试用例名
runner.run(all_case())
file.close()

五. 邮件推送测试报告

本文版权归作者和博客园共有,原创作者:http://www.cnblogs.com/BenLam,未经作者同意必须在文章页面给出原文连接。

通过邮件发送接口测试结果

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @file : 邮件.py
# @Date : 2018-06-02 14:14:46
# @Author : Destroyers (https://github.com/lguobin)
# @Link : https://github.com/lguobin
# @Version : $1.0$ import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication class Myemail:
def __init__(self,mail_list,mail_title):
self.mail_list = mail_list
self.mail_title = mail_title
self.mail_host = "smtp.163.com"
self.mail_user = "你自己邮箱@163.com"
self.mail_pass = "你的密码"
self.mail_postfix = "163.com" def SendMail(self):
info = self.mail_user + "<" + self.mail_user + "@" + self.mail_postfix + ">"
msg = MIMEMultipart()
msg['Subject'] = '接口测试报告'
msg['From'] = info
msg['To'] = ";".join(self.mail_list) with open("/temp/Report.html", 'r') as f:
Report_content = f.read().encode("utf-8")
puretext = MIMEText(Report_content, 'html', 'utf-8')
msg.attach(puretext)
try:
s = smtplib.SMTP() #创建邮件服务器对象
s.connect(self.mail_host) #连接到指定的smtp服务器。参数分别表示smpt主机和端口
s.login(self.mail_user, self.mail_pass) #登录到你邮箱
s.sendmail(me, self.mail_list, msg.as_string()) #发送内容
s.close()
return True
except Exception, e:
print str(e)
return False if __name__ == '__main__':
# 邮件登录
mailto_list = ["你领导的邮件@163,com","aaaa@163.com"]
mail_title = '接口测试报告:'
test = Myemail(mailto_list, mail_title)
print(test.SendMail())

本章节 End————下章再会

你的第一个接口测试:Python 接口测试的更多相关文章

  1. Python接口测试实战4(下) - 框架完善:用例基类,用例标签,重新运行上次失败用例

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  2. Python接口测试实战4(上) - 接口测试框架实战

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  3. Python接口测试实战1(下)- 接口测试工具的使用

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  4. Python接口测试框架实战与自动化进阶☝☝☝

    Python接口测试框架实战与自动化进阶☝☝☝  一.fiddler在工作中的运用  1.如何抓接口 抓紧手机端接口 ①.在电脑终端输入:ipconfig ,找到电脑ip ②.打开手机,连接WiFi, ...

  5. 零基础Python接口测试教程

    目录 一.Python基础 Python简介.环境搭建及包管理 Python基本语法 基本数据类型(6种) 条件/循环 文件读写(文本文件) 函数/类 模块/包 常见算法 二.接口测试快速实践 简单接 ...

  6. Python接口测试框架实战与自动化进阶✍✍✍

    Python接口测试框架实战与自动化进阶  整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受,单论单个知识点课程本身没问题,大家看 ...

  7. Python接口测试实战1(上)- 接口测试理论

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  8. Python接口测试实战5(上) - Git及Jenkins持续集成

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  9. Python接口测试实战5(下) - RESTful、Web Service及Mock Server

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  10. Python接口测试实战3(下)- unittest测试框架

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

随机推荐

  1. Mac 下 SVN 的使用

    在Windows环境中,我们一般使用TortoiseSVN来搭建svn环境.在Mac环境下,由于Mac自带了svn的服务器端和客户端功能,所以我们可以在不装任何第三方软件的前提下使用svn功能,不过还 ...

  2. Adapter(适配器)模式

    1. 概述: 接口的改变,是一个需要程序员们必须(虽然很不情愿)接受和处理的普遍问题.程序提供者们修改他们的代码;系统库被修正;各种程序语言以及相关库的发展和进化.  例子1:iphone4,你即可以 ...

  3. iOS dyld: Library not loaded 报错解决

    Xcode 用的是10.1 版本打的苹果包在 ios系统10.0 以上可以正常运行 但是系统9.3的手机安装后直接运行就崩溃 后来插上电脑联调 报错 dyld: Library not loaded: ...

  4. Angular7教程-06-页面与数据交互

    1. 本节说明 本节的内容会在上期搭建的框架基础上进行数据的填充,顺便回顾之前介绍过的插值表达式,属性绑定等知识,本节的数据只是在组件中模拟数据,后面会有专门的章节讲解如何从服务器获取数据. 2. 轮 ...

  5. pyntho经典面试题

    Python基础篇 1:为什么学习Python 2:通过什么途径学习Python 3:谈谈对Python和其他语言的区别 Python的优势: 4:简述解释型和编译型编程语言 5:Python的解释器 ...

  6. 06.搭建kafka集群环境并测试

    参考: https://www.cnblogs.com/zhangs1986/p/6565639.html https://www.cnblogs.com/frankdeng/p/9403883.ht ...

  7. PICT工具一键生成正交试验用例

    PICT工具一键生成正交试验用例 作用: 1.解决手动设计大量测试用例.或覆盖不全面问题,提高测试效率 2.读取excel,将生成的参数组合自动带入脚本,进行接口自动化测试 一.PICT简介 PICT ...

  8. Linux CentOS Python开发环境搭建教程

      CentOS安装Python 1.CentOS已经自带安装了2.x版本,先尝试python命令检查已安装的版本.如果你使用rpm.yum或deb命令安装过,请使用相对命令查询. 2.复制安装文件链 ...

  9. TINY4412:移植uboot、内核和挂接网络文件系统

    开发环境: 单板:TINY4412-1611 系统:Ubuntu 16.04 64位 编译工具链:arm-linux-gcc-4.3.2 uboot版本:uboot_tiny4412-20130729 ...

  10. R语言(自定义函数、循环语句、管道函数)

    学习R语言半年多了,以前比较注重统计方法上的学习,但是最近感觉一些基础知识也很重要.去年的参考资料是<R语言实战>,今年主要是看视频.推荐网易云课堂里的教程,很多资料都是很良心的~ 目前学 ...