1.基础知识
setUp和tearDown是每一次test_xx都会执行的,即使加上@classmethod也做不到每个类只执行一次
import unittest
class TestDemo001(unittest.TestCase):
@classmethod
def setUp(cls):
print("====setup========")
@classmethod
def tearDown(cls):
print("=====tearDown======")
def test_001(self):
print("======test001====")
def test_002(self):
print("======test002======")
if __name__ == "__main__":
unittest.main()
setUpClass和tearDownClass是每个类只执行一次,而且必须配合@classmethod才会生效
import unittest
class TestDemo001(unittest.TestCase):
@classmethod
def setUpClass(cls):
print("====setup========")
@classmethod
def tearDownClass(cls):
print("=====tearDown======")
def test_001(self):
print("======test001====")
def test_002(self):
print("======test002======")
if __name__ == "__main__":
unittest.main()
2.抽象requests方法
import requests
import json
data = {
"username":"aaa",
"password":"123123"
}
url = "http://c.m.163.com/nc/article/headline/T1348647853363/0-40.html"
class RunMain:
def __init__(self,url,method,data=None):
self.res = self.run_main(url,method,data)
def send_get(self,url,data=None):
result = requests.get(url).json()
return json.dumps(result,indent=2,sort_keys="true")
def send_post(self,url,data):
result = requests.post(url,data).json()
return json.dumps(result,indent=2,sort_keys="true")
def run_main(self,url,method,data=None):
res = None
if method == "GET":
res = self.send_get(url,data)
else:
res = self.send_post(url,data)
return res
if __name__ == "__main__":
run = RunMain(url,"GET",data)
print(run.res)
3、基本断言方法
基本的断言方法提供了测试结果是True还是False。所有的断言方法都有一个msg参数,如果指定msg参数的值,则将该信息作为失败的错误信息返回。
序号 | 断言方法 | 断言描述 |
---|---|---|
1 | assertEqual(arg1, arg2, msg=None) | 验证arg1=arg2,不等则fail |
2 | assertNotEqual(arg1, arg2, msg=None) | 验证arg1 != arg2, 相等则fail |
3 | assertTrue(expr, msg=None) | 验证expr是true,如果为false,则fail |
4 | assertFalse(expr,msg=None) | 验证expr是false,如果为true,则fail |
5 | assertIs(arg1, arg2, msg=None) | 验证arg1、arg2是同一个对象,不是则fail |
6 | assertIsNot(arg1, arg2, msg=None) | 验证arg1、arg2不是同一个对象,是则fail |
7 | assertIsNone(expr, msg=None) | 验证expr是None,不是则fail |
8 | assertIsNotNone(expr, msg=None) | 验证expr不是None,是则fail |
9 | assertIn(arg1, arg2, msg=None) | 验证arg1是arg2的子串,不是则fail |
10 | assertNotIn(arg1, arg2, msg=None) | 验证arg1不是arg2的子串,是则fail |
11 | assertIsInstance(obj, cls, msg=None) | 验证obj是cls的实例,不是则fail |
12 | assertNotIsInstance(obj, cls, msg=None) | 验证obj不是cls的实例,是则fail |
4、unittest的全局变量
1.setupclass里设置self.xxx变量,不同用例之间无法实时共享参数变动
2.setupclass里设置globals().["xxx"]变量,不同用例之间可以实时共享参数变动
3.setupclass里设置 ClassName.XXX变量,不同用例之间可以实时共享参数变动
4.setupclass之前设置 XXX变量
2.setupclass里设置globals().["xxx"]
from settings import *
import requests,json
import unittest
class Login(unittest.TestCase):
@classmethod
def setUpClass(self):
api_token = '/v1/api/common/getToken'
self.real_token_url = API_TEST_BASE_URL + api_token
globals()["token"] = None
def test_get_token(self):
r = requests.post(url=self.real_token_url)
globals()["token"] = json.loads(r.text)['model']['token']
print("第一个case获得的token:",globals()["token"])
return globals()["token"]
def test_get_u(self):
print("第二个case获得token值:",globals()["token"])
if __name__ == '__main__':
unittest.main()
执行结果:
第一个case获得的token: 44c5fcccca6c4e64a1c5d314b7ee22fc
第二个case获得token值: 44c5fcccca6c4e64a1c5d314b7ee22fc
3.setupclass里设置 ClassName.XXX变量
import unittest
class Mydemo(unittest.TestCase):
@classmethod
def setUpClass(cls):
Mydemo.a = "88"
def test1(self):
print("test1-----{}".format(Mydemo.a))
Mydemo.a = "99"
def test2(self):
print("test2-----{}".format(self.a))
print("test2_2---{}".format(Mydemo.a))
if __name__ == '__main__':
unittest.main()
复制代码
执行结果:
test1-----88
test2-----99
test2_2---99
4.setupclass之前设置 XXX变量
class AlienTest(unittest.TestCase):
status = 200
@classmethod
def setUpClass(cls):
cls.url = "http://www.baidu.com"
globals()['status'] = 300
def test_1_alien(self):
print("test_1_status:", self.status)
def test_2_alien(self):
self.status = 404
print("test_2_status", self.status)
def test_4_alien(self):
print("test_4_global_status", globals()['status'])
print("test_4_status", self.status)
if __name__ == '__main__':
unittest.main()
test_1_status: 200
test_2_status 404
test_4_global_status 300
test_4_status 200
5.unittest中方法的执行顺序
结论: unittest执行测试用例,默认是根据用例的方法名 的 ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z
那么如何控制用例执行顺序呢?
方式1,通过TestSuite类的addTest方法,按顺序加载测试用例
1 # coding=utf-8
2 #1.先设置编码,utf-8可支持中英文,如上,一般放在第一行
3
4 #2.注释:包括记录创建时间,创建人,项目名称。
5 '''
6 Created on 2019-4-23
7 @author: 北京-宏哥
8 Project:学习和使用unittest框架编写测试用例执行顺序
9 '''
10 #3.导入unittest模块
11 import unittest
12 #4.执行顺序和运行测试
13 import unittest
14
15 class TestLogin(unittest.TestCase):
16
17 def setUp(self):
18 pass
19 def test_login_blog(self):
20 """登录博客园
21
22 :return:
23 """
24 print("登录博客园")
25 def test_add_essay(self):
26 """ 添加随笔
27
28 :return:
29 """
30 print("添加随笔")
31 def test_release_essay(self):
32 """ 发布随笔
33
34 :return:
35 """
36 print("发布随笔")
37 def test_quit_blog(self):
38 """退出博客园
39
40 :return:
41 """
42 print("退出博客园")
43
44 def tearDown(self):
45 pass
46 if __name__ == '__main__':
47 # 启动单元测试
48 # unittest.main()
49
50 # 获取TestSuite的实例对象
51 suite = unittest.TestSuite()
52
53 # 将测试用例添加到测试容器中
54 suite.addTest(TestLogin('test_login_blog'))
55 suite.addTest(TestLogin('test_add_essay'))
56 suite.addTest(TestLogin('test_release_essay'))
57 suite.addTest(TestLogin('test_quit_blog'))
58
59 # 创建TextTestRunner类的实例对象
60 runner = unittest.TextTestRunner()
61 runner.run(suite)
62 #unittest.TextTestRunner(verbosity=3).run(suite)
方式2,通过修改函数名的方式
1 # coding=utf-8
2 #1.先设置编码,utf-8可支持中英文,如上,一般放在第一行
3
4 #2.注释:包括记录创建时间,创建人,项目名称。
5 '''
6 Created on 2019-4-23
7 @author: 北京-宏哥
8 Project:学习和使用unittest框架编写测试用例执行顺序
9 '''
10 #3.导入unittest模块
11 import unittest
12 #4.执行顺序和运行测试
13 import unittest
14
15 class TestLogin(unittest.TestCase):
16
17 def setUp(self):
18 pass
19 def test_1_login_blog(self):
20 """登录博客园
21
22 :return:
23 """
24 print("登录博客园")
25 def test_2_add_essay(self):
26 """ 添加随笔
27
28 :return:
29 """
30 print("添加随笔")
31 def test_3_release_essay(self):
32 """ 发布随笔
33
34 :return:
35 """
36 print("发布随笔")
37 def test_4_quit_blog(self):
38 """退出博客园
39
40 :return:
41 """
42 print("退出博客园")
43
44 def tearDown(self):
45 pass
46 if __name__ == '__main__':
47 # 启动单元测试
48 unittest.main()
6.unittest----skip装饰器
@
unittest.
skip
(reason) 无条件跳过用例,reason是说明原因
@
unittest.
skipIf
(condition, reason) condition为true的时候跳过
@unittest.skipUnless(condition, reason) condition为False的时候跳过
@
unittest.
expectedFailure
(Mark the test as an expected failure. If the test fails when run, the test is not counted as a failure.)将测试标记为预期的失败。 如果测试在运行时失败,则该测试不算作失败。
断言的时候跳过(暂时不知道有啥用,没看懂,貌似断言失败,也变成用例pass了。)
7. HTMLTestRunner生成报告
1、下载HTMLTestRunner报告(只是一个py文件),http://tungwaiyip.info/software/HTMLTestRunner_0_8_2/HTMLTestRunner.py
2、将该文件保存在python安装路径下的lib文件夹中。在文件中能import HTMLTestRunner成功,即配置成功
注意:
在python3中用HTMLTestRunner.py报importError“:No module named 'StringIO'解决办法
-
原因是官网的是python2语法写的,看官手动把官网的HTMLTestRunner.py改成python3的语法。
- 修改内容:
第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:
第631行,将print >> sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime)修改成print(sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime))
第766行,将uo = o.decode('latin-1')修改成uo = e
第772行,将ue = e.decode('latin-1')修改成ue = e
生成报告的代码:
import unittest
import HTMLTestRunner
class TestDemo001(unittest.TestCase):
@classmethod
def setUpClass(cls):
print("====setup========")
globals()["abc"] = "111"
@classmethod
def tearDownClass(cls):
print("=====tearDown======")
def test_002(self):
print("======test002======")
res = "1001"
print("globals()[\"abc\"]===", globals()["abc"])
#self.assertEqual(res,"1001","测试成功")
def test_001(self):
print("======test001====")
res = "1000"
print("globals()[\"abc\"]===",globals()["abc"])
#self.assertEqual(res, "1001", "测试成功")
@unittest.skip("test_bw")
def test_000(self):
print("======000====")
globals()["abc"] = "000"
print("globals()[\"abc\"]===", globals()["abc"])
if __name__ == "__main__":
#unittest.main()
suite = unittest.TestSuite()
suite.addTest(TestDemo001("test_001"))
suite.addTest(TestDemo001("test_002"))
filepath = "../report/demo001.html"
f = open(filepath,"wb")
run = HTMLTestRunner.HTMLTestRunner(stream=f,title="这是一个demo001测试报告")
run.run(suite)
关于python3 使用pycharm+unittest+html+HTMLTestRunner 测试用例运行正常,但却不能生成测试报告的解决方法
该方法适用于以下条件:
1.运行测试用例一切正常,只是没有测试报告显示
2.使用命令行pyhon 脚本名字.py 却可以生成测试报告
pycharm 在运行测试用例的时候 默认是以unittest 框架来运行的,所以不能生成测试报告
如何判断是否是用unitest框架运行的呢?
运行完成后,如果发现右上角有unittest in ***** ,说明是以框架的方式来运行的
设置运行方式如已下步骤,设置完成后,再运行就能够生产报告了
1、如何使用python开发测试框架?
python开发,request进行网络请求,unnitest管理case(断言,跳过),生成测试报告(HTMLTestRunner),数据的存储,持续集成(批处理文件),
2、如何管理case
两个case之间有依赖:skip,case写在excel
3.简述case的执行
case的执行顺序
4.如何解决case的依赖
全局变量
5.如何生成测试报告
HTMLTesTRunner