python 自动化接口测试

接口测试自动化的优点:

1,web自动化说起来很多人都会直接想到UI自动化这个设计,很少有人直接第一个概念是接口自动化,接口测试的开发更加快捷方便,维护工作比起UI自动化更加容易,例如:有一个项目,做完第一周期以后,后面需求变动,所有的页面都需要更换,功能稍有变动,这时候ui自动化维护起来就比较麻烦,工作量较大,所有的页面对面都需要从新进行封装调试,这时候如果只是接口自动化,接口不发生改变,完全可以不用就行太多的维护修改。这样节省了很多的时间,而且接口自动化的开发有一个好处是,不用完全等到页面设计开发完成后才进行,只要后台开发员的功能接口设计开发完成,测试人员就可以进行设计开发脚本。

先看实际效果地址:


1,收到的邮件+附件

邮件的打开效果:


这就是我们最终生成的结果,看着还不错吧,接下来我们就来配置一下环境然后做个小小的测试

一、配置python虚拟环境基于windows,基于Linux的配置百度有很多,这里不再赘述;



前言

由于Python的版本众多,还有Python2和Python3的争论,因此有些软件包或第三方库就容易出现版本不兼容的问题。

通过 virtualenv 这个工具,就可以构建一系列 虚拟的Python环境 ,然后在每个环境中安装需要的软件包(配合 pip 使用),这一系列的环境是相互隔离的。作为一个独立的环境就不容易出现版本问题,还方便部署。

安装

pip install virtualenv

virtualenv的基本使用

3.1 创建虚拟环境

virtualenv venv

为环境指定Python解释器:

virtualenv -p c:\python27\python.exe venv #python2

virtualenv -p c:\python36\python.exe venv #python3

3.2 激活虚拟环境

activate venv

3.3 停止虚拟环境

deactivate

3.4 删除虚拟环境

直接删除目录即可.

rmvirtualenv venv


二、python单元测试之unittest框架使用;


一、什么是单元测试

单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。

比如对于函数abs(),我们可以编写的测试用例为:

(1)输入正数,比如1、1.2、0.99,期待返回值与输入相同

(2)输入复数,比如-1、-1.2、-0.99,期待返回值与输入相反

(3)输入0,期待返回0

(4)输入非数值类型,比如None、[]、{}、期待抛出TypeError

把上面这些测试用例放到一个测试模块里,就是一个完整的单元测试

二、unittest工作原理

unittest中最核心的四部分是:TestCase,TestSuite,TestRunner,TestFixture

(1)一个TestCase的实例就是一个测试用例。测试用例就是指一个完整的测试流程,包括测试前准备环境的搭建(setUp),执行测试代码(run),以及测试后环境的还原(tearDown)。元测试(unit test)的本质也就在这里,一个测试用例是一个完整的测试单元,通过运行这个测试单元,可以对某一个问题进行验证。

(2)而多个测试用例集合在一起,就是TestSuite,而且TestSuite也可以嵌套TestSuite。

(3)TestLoader是用来加载TestCase到TestSuite中的。

(4)TextTestRunner是来执行测试用例的,其中的run(test)会执行TestSuite/TestCase中的run(result)方法

(5)测试的结果会保存到TextTestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息。

综上,整个流程就是首先要写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,整个过程集成在unittest.main模块中。

三、下面举两个实例,来看看unittest如何测试一个简单的函数

(1)编写一个Dict类,这个类的行为和dict一致,但是可以通过属性来访问例如

[python] view plain copy

>>> d = Dict(a=1, b=2) 

>>> d['a'] 

>>> d.a 

mydict.py代码如下:

[python] view plain copy

class Dict(dict): 

    def __init__(self, **kwargs): 

        super(Dict, self).__init__(**kwargs) 


    def __getattr__(self, key): 

        try: 

            return self[key] 

        except KeyError: 

            raise AttributeError(r"'Dict' object has no attribute '%s'" % key) 


    def __setattr__(self, key, value): 

        self[key] = value 


用于测试的文件mydict_test.py代码如下:

[python] view plain copy

import unittest 

from mydict import Dict 



class TestDict(unittest.TestCase): 

    def test_init(self): 

        d = Dict(a=1, b='test') 

        self.assertEqual(d.a, 1)  # 判断d.a是否等于1 

        self.assertEqual(d.b, 'test')  # 判断d.b是否等于test 

        self.assertTrue(isinstance(d, dict))  # 判断d是否是dict类型 


    def test_key(self): 

        d = Dict() 

        d['key'] = 'value' 

        self.assertEqual(d.key, 'value') 


    def test_attr(self): 

        d = Dict() 

        d.key = 'value' 

        self.assertTrue('key' in d) 

        self.assertEqual(d['key'], 'value') 


    def test_keyerror(self): 

        d = Dict() 

        with self.assertRaises(KeyError):  # 通过d['empty']访问不存在的key时,断言会抛出keyerror 

            value = d['empty'] 


    def test_attrerror(self): 

        d = Dict() 

        with self.assertRaises(AttributeError):  # 通过d.empty访问不存在的key时,我们期待抛出AttributeError 

            value = d.empty 



if __name__ == '__main__': 

    unittest.main() 

直接把mydict_test.py当普通的Python脚本运行即可

输出:

[python] view plain copy

..... 

---------------------------------------------------------------------- 

Ran 5 tests in 0.000s 


OK 

(2)测一个简单的加减乘除接口

mathfunc.py文件代码如下:

[python] view plain copy

def add(a, b): 

    return a + b 


def minus(a, b): 

    return a - b 


def multi(a, b): 

    return a * b 


def divide(a, b): 

    return a / b 

test_mathfunc.py文件代码如下:

[python] view plain copy

import unittest 

from mathfunc import * 


class TestMathFunc(unittest.TestCase): 


    def test_add(self): 

        self.assertEqual(3, add(1, 2)) 

        self.assertNotEqual(3, add(2, 2)) 


    def test_minus(self): 

        self.assertEqual(1, minus(3, 2)) 


    def test_multi(self): 

        self.assertEqual(6, multi(3, 2)) 


    def test_divide(self): 

        self.assertEqual(2, divide(6, 3)) 

        self.assertEqual(2.5, divide(5, 2)) 


if __name__ == '__main__': 

    unittest.main() 

输出:

[python] view plain copy

.F.. 

====================================================================== 

FAIL: test_divide (__main__.TestDict) 

---------------------------------------------------------------------- 

Traceback (most recent call last): 

  File "D:/pythonWorkspace/test_mathfunc.py", line 20, in test_divide 

    self.assertEqual(2.5, divide(5, 2)) 

AssertionError: 2.5 != 2 


---------------------------------------------------------------------- 

Ran 4 tests in 0.000s 


FAILED (failures=1) 

可以看到一共运行了4个测试,失败了1个,并且给出了失败原因,2.5!=2,也就是说我们的divide方法是有问题的。

关于输出的几点说明:

1、在第一行给出了每一个用例执行的结果的标识,成功是.,失败是F,出错是E,跳过是S。从上面可以看出,测试的执行跟方法的顺序没有关系,divide方法写在了第4个,但是却在第2个执行。

2、每个测试方法均以test开头,否则不能被unittest识别

3、在uniitest.main()中加verbosity参数可以控制输出的错误报告的详细程度,默认是1,如果设为0, 则不输出每一用例的执行结果,即没有上面的结果中的第1行,如果设为2,则输出详细的执行结果,如下所示:

[python] view plain copy

test_add (__main__.TestMathFunc) ... ok 

test_divide (__main__.TestMathFunc) ... FAIL 

test_minus (__main__.TestMathFunc) ... ok 

test_multi (__main__.TestMathFunc) ... ok 


====================================================================== 

FAIL: test_divide (__main__.TestMathFunc) 

---------------------------------------------------------------------- 

Traceback (most recent call last): 

  File "D:/pythonWorkspace/test_mathfunc.py", line 20, in test_divide 

    self.assertEqual(2.5, divide(5, 2)) 

AssertionError: 2.5 != 2 


---------------------------------------------------------------------- 

Ran 4 tests in 0.000s 


FAILED (failures=1) 

四、组织TestSuite

上面的测试用例在执行的时候没有按照顺序执行,如果想要让用例按照你设置的顺序执行就用到了TestSuite。我们添加到TestSuite中的case是会按照添加的顺序执行的。

现在我们只有一个测试文件,如果有多个测试文件,也可以用TestSuite组织起来。

继续上面第二加减乘除的例子,现在再新建一个文件,test_suite.py,代码如下:

[python] view plain copy

# coding=utf-8 

import unittest 

from test_mathfunc import TestMathFunc 


if __name__ == '__main__': 

    suite = unittest.TestSuite() 


    tests = [TestMathFunc("test_add"), TestMathFunc("test_minus"), TestMathFunc("test_divide")] 

    suite.addTests(tests) 


    runner = unittest.TextTestRunner(verbosity=2) 

    runner.run(suite) 

执行结果如下:

[python] view plain copy

test_add (test_mathfunc.TestMathFunc) ... ok 

test_minus (test_mathfunc.TestMathFunc) ... ok 

test_divide (test_mathfunc.TestMathFunc) ... FAIL 


====================================================================== 

FAIL: test_divide (test_mathfunc.TestMathFunc) 

---------------------------------------------------------------------- 

Traceback (most recent call last): 

  File "D:\pythonWorkspace\HTMLTest\test_mathfunc.py", line 20, in test_divide 

    self.assertEqual(2.5, divide(5, 2)) 

AssertionError: 2.5 != 2 


---------------------------------------------------------------------- 

Ran 3 tests in 0.000s 


FAILED (failures=1) 

五、将结果输出到文件

现在我们的测试结果只能输出到控制台,现在我们想将结果输出到文件中以便后续可以查看。

将test_suite.py进行一点修改,代码如下:

[python] view plain copy

# coding=utf-8 


import unittest 

from test_mathfunc import TestMathFunc 


if __name__ == '__main__': 

    suite = unittest.TestSuite() 


    tests = [TestMathFunc("test_add"), TestMathFunc("test_minus"), TestMathFunc("test_divide")] 

    suite.addTests(tests) 


    with open('UnittestTextReport.txt', 'a') as  f: 

        runner = unittest.TextTestRunner(stream=f, verbosity=2) 

        runner.run(suite) 


运行该文件,就会发现目录下生成了'UnittestTextReport.txt,所有的执行报告均输出到了此文件中。

六、test fixture的setUp和tearDown

当遇到要启动一个数据库这种情况时,只想在开始时连接上数据库,在结束时关闭连接。那么可以使用setUp和tearDown函数。

[python] view plain copy

class TestDict(unittest.TestCase): 


    def setUp(self): 

        print 'setUp...' 


    def tearDown(self): 

        print 'tearDown...' 

这两个方法在每个测试方法执行前以及执行后执行一次,setUp用来为测试准备环境,tearDown用来清理环境,以备后续的测试。

如果想要在所有case执行之前准备一次环境,并在所有case执行结束之后再清理环境,我们可以用setUpClass()与tearDownClass(),代码格式如下:

[python] view plain copy

class TestMathFunc(unittest.TestCase): 

    @classmethod 

    def setUpClass(cls): 

        print "setUp" 


    @classmethod 

    def tearDownClass(cls): 

        print "tearDown" 

七、跳过某个case

unittest提供了几种方法可以跳过case

(1)skip装饰器

代码如下

[python] view plain copy

# coding=utf-8 

import unittest 

from mathfunc import * 


class TestMathFunc(unittest.TestCase): 


    ..... 


    @unittest.skip("i don't want to run this case.") 

    def test_minus(self): 

        self.assertEqual(1, minus(3, 2)) 

输出:

[python] view plain copy

test_add (test_mathfunc.TestMathFunc) ... ok 

test_minus (test_mathfunc.TestMathFunc) ... skipped "i don't want to run this case." 

test_divide (test_mathfunc.TestMathFunc) ... FAIL 


====================================================================== 

FAIL: test_divide (test_mathfunc.TestMathFunc) 

---------------------------------------------------------------------- 

Traceback (most recent call last): 

  File "D:\pythonWorkspace\HTMLTest\test_mathfunc.py", line 28, in test_divide 

    self.assertEqual(2.5, divide(5, 2)) 

AssertionError: 2.5 != 2 


---------------------------------------------------------------------- 

Ran 3 tests in 0.000s 


FAILED (failures=1, skipped=1) 

skip装饰器一共有三个

unittest,skip(reason):无条件跳过

unittest.skipIf(condition, reason):当condition为True时跳过

unittest.skipUnless(condition, reason):当condition为False时跳过

(2)TestCase.skipTest()方法

[python] view plain copy

class TestMathFunc(unittest.TestCase): 

... 

def test_minus(self): 

        self.skipTest('do not run this.') 

        self.assertEqual(1, minus(3, 2)) 

输出:

[python] view plain copy

test_add (test_mathfunc.TestMathFunc) ... ok 

test_minus (test_mathfunc.TestMathFunc) ... skipped 'do not run this.' 

test_divide (test_mathfunc.TestMathFunc) ... FAIL 


====================================================================== 

FAIL: test_divide (test_mathfunc.TestMathFunc) 

---------------------------------------------------------------------- 

Traceback (most recent call last): 

  File "D:\pythonWorkspace\HTMLTest\test_mathfunc.py", line 20, in test_divide 

    self.assertEqual(2.5, divide(5, 2)) 

AssertionError: 2.5 != 2 


---------------------------------------------------------------------- 

Ran 3 tests in 0.000s 


FAILED (failures=1, skipped=1) 

此处涉及到HTMLTestRunner稍后在下方给出配置;

八、用HTMLTestRunner输出漂亮的HTML报告

txt格式的文本执行报告过于简陋,这里我们学习一下借助HTMLTestRunner生成HTML报告。首先需要下载HTMLTestRunner.py,并放到当前目录下,或者python目录下的Lib中,就可以导入运行了。

下载地址:http://tungwaiyip.info/software/HTMLTestRunner.html

将test_suite.py代码修改如下:

[python] view plain copy

# coding=utf-8 


import unittest 

from test_mathfunc import TestMathFunc 

from HTMLTestRunner import HTMLTestRunner 



if __name__ == '__main__': 

    suite = unittest.TestSuite() 


    tests = [TestMathFunc("test_add"), TestMathFunc("test_minus"), TestMathFunc("test_divide")] 

    suite.addTests(tests) 


    with open('HTMLReport.html', 'w') as f: 

        runner = HTMLTestRunner(stream=f, 

                                title = 'MathFunc Test Report', 

                                description='generated by HTMLTestRunner.', 

                                verbosity=2 

                                ) 

        runner.run(suite) 

执行后,控制台输出如下:

[python] view plain copy

ok test_add (test_mathfunc.TestMathFunc) 

F  test_divide (test_mathfunc.TestMathFunc) 


Time Elapsed: 0:00:00.001000

生成的html:

[link](https://img-blog.csdn.net/20170713182044771)

九、总结

1、unittest是python自带的单元测试框架,我们可以用其来作为我们自动化测试框架的用例组织执行框架。

2、unittest的流程:写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,我们通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者我们可以直接通过TextTestRunner来执行用例。

3、一个class继承unittest.TestCase即是一个TestCase,其中以 test 开头的方法在load时被加载为一个真正的TestCase。

4、verbosity参数可以控制执行结果的输出,0 是简单报告、1 是一般报告、2 是详细报告。

5、可以通过addTest和addTests向suite中添加case或suite,可以用TestLoader的loadTestsFrom__()方法。

6、用 setUp()、tearDown()、setUpClass()以及 tearDownClass()可以在用例执行前布置环境,以及在用例执行后清理环境

7、我们可以通过skip,skipIf,skipUnless装饰器跳过某个case,或者用TestCase.skipTest方法。

8、参数中加stream,可以将报告输出到文件:可以用TextTestRunner输出txt报告,以及可以用HTMLTestRunner输出html报告。


三、python 之requests

requests由于它的强大的API现在有很多是用在爬虫方面,所有做接口测试成了很好的选择;

下面我们来看一下它的基本用法;


python requests 官方中文文档:http://docs.python-requests.org/zh_CN/latest/user/quickstart.htmlRequests 是用Python语言编写,基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP 库。它比 urllib 更加方便,可以节约我们大量的工作,完全满足 HTTP 测试需求。Requests 的哲学是以 PEP 20 的习语为中心开发的,所以它比 urllib 更加 Pythoner。更重要的一点是它支持 Python3 !Beautiful is better than ugly.(美丽优于丑陋)Explicit is better than implicit.(清楚优于含糊)Simple is better than complex.(简单优于复杂)Complex is better than complicated.(复杂优于繁琐)Readability counts.(重要的是可读性)一、安装 Requests通过pip安装pip install requests或者,下载代码后安装:$ git clone git://github.com/kennethreitz/requests.git$ cd requests$ python setup.py install再懒一点,通过IDE安装吧,如pycharm!二、发送请求与传递参数先来一个简单的例子吧!让你了解下其威力:import requests r = requests.get(url='http://www.itwhy.org') # 最基本的GET请求print(r.status_code) # 获取返回状态r = requests.get(url='http://dict.baidu.com/s', params={'wd':'python'}) #带参数的GET请求print(r.url)print(r.text) #打印解码后的返回数据很简单吧!不但GET方法简单,其他方法都是统一的接口样式哦!requests.get(‘https://github.com/timeline.json’) #GET请求requests.post(“http://httpbin.org/post”) #POST请求requests.put(“http://httpbin.org/put”) #PUT请求requests.delete(“http://httpbin.org/delete”) #DELETE请求requests.head(“http://httpbin.org/get”) #HEAD请求requests.options(“http://httpbin.org/get”) #OPTIONS请求我们一般用到的只有get和post 接下来我们只考虑get 和 post请求PS:以上的HTTP方法,对于WEB系统一般只支持 GET 和 POST,有一些还支持 HEAD 方法。带参数的请求实例:import requestsrequests.get('http://www.dict.baidu.com/s', params={'wd': 'python'}) #GET参数实例requests.post('http://www.itwhy.org/wp-comments-post.php', data={'comment': '测试POST'}) #POST参数实例POST发送JSON数据:import requestsimport json r = requests.post('https://api.github.com/some/endpoint', data=json.dumps({'some': 'data'}))print(r.json())定制header:import requestsimport json data = {'some': 'data'}headers = {'content-type': 'application/json', 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:22.0) Gecko/20100101 Firefox/22.0'} r = requests.post('https://api.github.com/some/endpoint', data=data, headers=headers)print(r.text)三、Response对象使用requests方法后,会返回一个response对象,其存储了服务器响应的内容,如上实例中已经提到的 r.text、r.status_code……获取文本方式的响应体实例:当你访问 r.text 之时,会使用其响应的文本编码进行解码,并且你可以修改其编码让 r.text 使用自定义的编码进行解码。r = requests.get('http://www.itwhy.org')print(r.text, '\n{}\n'.format('*'*79), r.encoding)r.encoding = 'GBK'print(r.text, '\n{}\n'.format('*'*79), r.encoding)其他响应:r.status_code #响应状态码r.raw #返回原始响应体,也就是 urllib 的 response 对象,使用 r.raw.read() 读取r.content #字节方式的响应体,会自动为你解码 gzip 和 deflate 压缩r.text #字符串方式的响应体,会自动根据响应头部的字符编码进行解码r.headers #以字典对象存储服务器响应头,但是这个字典比较特殊,字典键不区分大小写,若键不存在则返回None#*特殊方法*#r.json() #Requests中内置的JSON解码器r.raise_for_status() #失败请求(非200响应)抛出异常例:import requests URL = 'http://ip.taobao.com/service/getIpInfo.php' # 淘宝IP地址库APItry: r = requests.get(URL, params={'ip': '8.8.8.8'}, timeout=1) r.raise_for_status() # 如果响应状态码不是 200,就主动抛出异常except requests.RequestException as e: print(e)else: result = r.json() print(type(result), result, sep='\n') 四、上传文件使用 Requests 模块,上传文件也是如此简单的,文件的类型会自动进行处理:import requests url = 'http://127.0.0.1:5000/upload'files = {'file': open('/home/lyb/sjzl.mpg', 'rb')}#files = {'file': ('report.jpg', open('/home/lyb/sjzl.mpg', 'rb'))} #显式的设置文件名 r = requests.post(url, files=files)print(r.text)更加方便的是,你可以把字符串当着文件进行上传:import requests url = 'http://127.0.0.1:5000/upload'files = {'file': ('test.txt', b'Hello Requests.')} #必需显式的设置文件名 r = requests.post(url, files=files)print(r.text)五、Cookies与会话对象如果某个响应中包含一些Cookie,你可以快速访问它们:import requests r = requests.get('http://www.google.com.hk/')print(r.cookies['NID'])print(tuple(r.cookies))要想发送你的cookies到服务器,可以使用 cookies 参数:import requests url = 'http://httpbin.org/cookies'cookies = {'testCookies_1': 'Hello_Python3', 'testCookies_2': 'Hello_Requests'}# 在Cookie Version 0中规定空格、方括号、圆括号、等于号、逗号、双引号、斜杠、问号、@,冒号,分号等特殊符号都不能作为Cookie的内容。r = requests.get(url, cookies=cookies)print(r.json())会话对象让你能够跨请求保持某些参数,最方便的是在同一个Session实例发出的所有请求之间保持cookies,且这些都是自动处理的,甚是方便。下面就来一个真正的实例,如下是快盘签到脚本:import requests headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Encoding': 'gzip, deflate, compress', 'Accept-Language': 'en-us;q=0.5,en;q=0.3', 'Cache-Control': 'max-age=0', 'Connection': 'keep-alive', 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:22.0) Gecko/20100101 Firefox/22.0'} s = requests.Session()s.headers.update(headers)s.get('https://www.kuaipan.cn/account_login.htm') _URL = 'http://www.kuaipan.cn/index.php's.post(_URL, params={'ac':'account', 'op':'login'}, data={'username':'****@foxmail.com', 'userpwd':'********', 'isajax':'yes'})r = s.get(_URL, params={'ac':'zone', 'op':'taskdetail'})print(r.json())s.get(_URL, params={'ac':'common', 'op':'usersign'})六、超时与异常timeout 仅对连接过程有效,与响应体的下载无关。>>> requests.get('http://github.com', timeout=0.001)Traceback (most recent call last): File "", line 1, inrequests.exceptions.Timeout: HTTPConnectionPool(host='github.com', port=80): Request timed out. (timeout=0.001)

所有Requests显式抛出的异常都继承自 requests.exceptions.RequestException:ConnectionError、HTTPError、Timeout、TooManyRedirects。

本文摘自:https://www.cnblogs.com/mrchige/p/6409444.html


四、HTMLTestRunner 配置方式


HTMLTestRunner修改成Python3版本

修改前:HTMLTestRunner下载地址:http://tungwaiyip.info/software/HTMLTestRunner.html

    BSTestRunner    下载地址:https://github.com/easonhan007/HTMLTestRunner

修改后:HTMLTestRunner下载地址:https://pan.baidu.com/s/1W6e_Bqg9dZTkVOWUP93XkA

    BSTestRunner    下载地址:https://pan.baidu.com/s/1nuJLWYdbq5ur8qoOSUq-8A

修改方法:

第94行,将import StringIO修改成import io

第539行,将self.outputBuffer = StringIO.StringIO()修改成self.outputBuffer = io.StringIO()

第642行,将if not rmap.has_key(cls):修改成if not cls in rmap:

第766行,将uo = o.decode('latin-1')修改成uo = e

第775行,将ue = e.decode('latin-1')修改成ue = e

第631行,将print >> sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime)修改成print(sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime))

测试结果:

HTMLTestRunner

[link](https://images2018.cnblogs.com/blog/1297862/201803/1297862-20180307224515781-305484153.png)

BSTestRunner

[link](https://images2018.cnblogs.com/blog/1297862/201803/1297862-20180307235635421-1293268562.png)

这里附上HTMLTestRunner GitHub 下载地址,支持py2和py3的中文版,下载直接放到当前目录下或者放置到python的Lib下:https://github.com/findyou/HTMLTestRunnerCN

英文版test [link](https://github.com/findyou/python/raw/master/Report_EN.gif)

中文版test [link](https://github.com/findyou/python/raw/master/Report_CN.gif)


所有的都配置好以后我们就可以看是实际操作了;

下面先附上目录


整体的框架很多是配置主要部分在于测试脚本,我们先看一下配置内容:

首先看一下工具,也就是utils下的common.py文件,这是放置的是发送邮件的内容:


然后是config.py文件,里面放置的是关于发送邮件相关的配置,账号,授权码,还有要接受人的账号;


然后就是启动文件;


这些配置好以后就可以在TestCase目录下编写测试相关的脚本文件;


部分示例,这个例子是先要在登录的状态下,保持回话去测试其他接口,这个例子是先模拟登录然后使用requests 的session去保持登录状态发测试其他接口,还有一种方案是可以使用requests的post方法携带登录后的cookies进行操作,结果是一样的

具体步骤不在此展示;最后运行我们的启动文件就可以了,最终结果在最上方;

同时因为unittest的灵活性我们可以尝试使用virtualenv+unittest+selenium+HTMLTestRunner框架来进行功能方面的自动化测试;我们只需将写好的测试脚本放置到TestCase文件下即可;


这个只是一个简单的demo在某个页面进行截图保存;

更加复杂的功能逻辑性的操作要针对业务场景来自己定义;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容