首先咱們先明確一個概念,什麼叫接口、什麼叫接口測試?javascript
接口的全稱叫【Application Programming Interface 又叫API】,是提供應用程序與開發人員基於某軟件或硬件得以訪問一組例程的能力,而又無需訪問源碼,或理解內部工做機制的細節。css
接口測試是測試系統組件間接口的一種測試。接口測試主要用於檢測外部系統與系統之間以及內部各個子系統之間的交互點。測試的重點是要檢查數據的交換,傳遞和控制管理過程,以及系統間的相互邏輯依賴關係等。html
(本章不會講POSTMan、Jmeter等工具,直接入直路,工具畢竟是有依賴性)java
本文版權歸做者和博客園共有,原創做者:http://www.cnblogs.com/BenLam,未經做者贊成必須在文章頁面給出原文鏈接。python
一、Python3.7 + notepad (Windows自帶的文本文檔工具)|(Linux配合vi編輯也能夠)git
二、Request庫:下載地址 或經過Pip命令安裝lib庫:github
pip install requests
三、urllib、Unittestjson
四、HTMLTestRunner獲取方法【打開下面摺疊代碼,另存爲HTMLTestRunner_Py3.Py文件】
api
#!/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)
演示接口:豆瓣電影搜索服務器
文檔說明:https://developers.douban.com/wiki/?title=movie_v2#search
api請求地址:https://api.douban.com/v2/movie/search?
一、按片名搜索:api請求地址 + q=鋼鐵俠
二、按類型搜索:api請求地址 + tag=喜劇
說明:在實際工做中接口說明開發會提供交到咱們手上的,不用擔憂。
一、拿到 api 先彆着急測試,經過手工點點可否正常使用
二、編寫對應的測試用例,例如上邊測試按電影的片名和類型搜索:(演示)
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=
本文版權歸做者和博客園共有,原創做者: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)
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內容。
本文版權歸做者和博客園共有,原創做者: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("測試不經過")
使用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 = "1" b = "2" 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' - 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————下章再會