本篇博客
unittest模块
1 unittest基本概念
2 unittest基本用法
3 unittest断言
4 unittest命令行接口
5 unittest与selenium
unittest模块
1 unittest基本概念
1) 什么是是unittest框架?
Unittest单元测试框架是专门用来进行测试的框架
2) 主要概念:
test fixture: 代表了用例执行前的准备工作和用例执行之后的清理工作。
test fixture
test case: 测试用例,这个相信大家都不陌生。是测试的最小单位,一般检查一组输入的响应(输出)是否符合预期。unittest模块提供了TestCase类来帮助我们创建测试用例;
test case
test suite: 经常被翻译成”测试套件”,也有人称为”测试套”,是测试用例或测试套件的集合,一般用来把需要一起执行的用例组合到一起;
test suite
test runner: 用来执行测试用例并输出测试结果的组件。可以是图形界面或命令行界面;
test runner
2 unittest基本用法
unittest基本用法:
1.通过继承unittest.TestCase进行编写,继承unittest.TestCase的类会被框架识别为测试用例。
2.setUp和TearDown是用于事前和事后做相关处理动作的,就是前面说的Test Fixture,会在每个测试用例运行前后被框架自动调用
3.所有以test开头的方法会被框架自动识别为测试用例,并自动调用执行,不是以test开头的不会被调用
4.unittest.main()是最简单的测试执行方式
5.调用unittest.main()方法后,继承自unittest.TestCase类的类会被自动识别为测试用例并且被调用。
6.test suite: 经常被翻译成”测试套件”,(另一种测试调用方法)也有人称为”测试套”,是测试用例或测试套件的集合,一般用来把需要一起执行的用例组合到一起;
案例1:简单测试
1.unittest.main()运行时,框架自动寻找TestCase子类,并且运行
2.在TestCase类中,只把以test开头的方法当做测试用例,然后执行,是有顺序的,字母或者数字。
# 导入unittest模块 import unittest # 继承TestCase类,TestCase类是测试用例类 class Test1(unittest.TestCase): def test_001(self): print('001') def test_003(self): print('003') def test_002(self): print('002') if __name__ == '__main__': unittest.main()
案例2:Test1,Test2都会被调用。因为都继承了TestCase
# 导入unittest模块 import unittest # 继承TestCase类,TestCase类是测试用例类 class Test1(unittest.TestCase): def test_001(self): print('001') def test_002(self): print('002') def test_003(self): print('003') class Test2(unittest.TestCase): def test_001(self): print('201') def test_002(self): print('202') if __name__ == '__main__': unittest.main()
案例3:
1 setUp()用于初始化一些参数,在测试用例执行前自动被调用
2 tearDown()用于清理,在测试用例执行后被调用
# 导入unittest模块 import unittest # 继承TestCase类,TestCase类是测试用例类 class Test1(unittest.TestCase): def setUp(self): print('hello') def tearDown(self): print('bye') def test_001(self): print('001') def test_002(self): print('002') def test_003(self): print('003') if __name__ == '__main__': unittest.main() # 1.unittest.main()运行时,框架自动寻找TestCase子类,并且运行 # 2.在TestCase类中,只把以test开头的方法当做测试用例,然后执行 # 3.setUp()用于初始化一些参数,在测试用例执行前自动被调用,tearDown()用于清理,在测试用例执行后被调用 # 4.setUp,tearDown。每个用例开始和结束调用相应的代码。
test suite: 经常被翻译成”测试套件”,也有人称为”测试套”,是测试用例或测试套件的集合,一般用来把需要一起执行的用例组合到一起;
下面是测试套件的用法:
1.创建测试套件
suit = unittest.TestSuite()
2. 定义一个测试用例列表,逐个添加
case_list= ['test_001','test_002','test_003'] for case in case_list: suit.addTest(Test1(case))
3.运行测试用例,verbosity=2(固定)为每一个测试用例输出报告,run的参数是测试套件
unittest.TextTestRunner(verbosity=2).run(suit)
案例4:测试套件
# 导入unittest模块 import unittest # 继承TestCase类,TestCase类是测试用例类 class Test1(unittest.TestCase): def setUp(self): print('hello') def tearDown(self): print('bye') def test_001(self): print('001') def test_002(self): print('002') def test_003(self): print('003') if __name__ == '__main__': # 第一种调用: # unittest.main() # 第二种调用 # 创建测试套件 suit = unittest.TestSuite() # 定义一个测试用例列表 case_list= ['test_001','test_002','test_003'] for case in case_list: suit.addTest(Test1(case)) # 运行测试用例,verbosity=2为每一个测试用例输出报告,run的参数是测试套件 unittest.TextTestRunner(verbosity=2).run(suit)
3 unittest断言
unittest断言:
断言是测试用例的核心。我们使用assertEqual()来判断预期结果,用assertTrue()和assertFalse来做是非判断。
案例:断言测试
import unittest class Test(unittest.TestCase): def setUp(self): print('start') def tearDown(self): print('bye') def test_001(self): self.assertEqual('1','1') def test_002(self): self.assertEqual('1','0') if __name__ == '__main__': unittest.main()
跑了2个测试用例,一个通过,一个失败。期待为1,结果为0。
显示代码错误的地方:
4 unittest命令行接口
unittest命令行接口:
unittest支持命令行接口,我们可以在命令行里指定运行具体的测试用例。
python -m unittest test.Tese1
5 unittest与selenium
unittest与selenium
前面我们简单学习了unittest的用法,接下来我们将unittest与selenium融合在一起进行web自动化测试
目录结构:
1. Commonlib目录存放通用模块(我们封装的selenium模块)
2. 创建Business目录 ,根据业务创建测试功能模块
3. 创建Testcase目录存放测试用例
1. Commonlib-Commonlib.py(后面会用到)
from selenium import webdriver import time class Commonshare(object): # 初始化方法 def __init__(self): # 创建浏览器对象 self.driver = webdriver.Firefox() # 设置隐式等待 self.driver.implicitly_wait(5) # 设置浏览器的最大化 self.driver.maximize_window() def open_url(self,url): # 请求指定站点 self.driver.get(url) time.sleep(3) def locateElement(self, locate_type, value): # 判断定位方式并调用相关方法 el = None if locate_type == 'id': el = self.driver.find_element_by_id(value) elif locate_type == 'name': el = self.driver.find_element_by_name(value) elif locate_type == 'class': el = self.driver.find_element_by_class_name(value) elif locate_type == 'text': el = self.driver.find_element_by_link_text(value) elif locate_type == 'xpath': el = self.driver.find_element_by_xpath(value) elif locate_type == 'css': el = self.driver.find_element_by_css_selector(value) # 如果el不为None,则返回 if el is not None: return el # 指定对某一元素的点击操作 def click(self, locate_type, value): # 调用定位方法进行元素定位 el = self.locateElement(locate_type,value) # 执行点击操作 el.click() time.sleep(1) # 对指定的元素进行数据输入 def input_data(self,locate_type,value,data): # 调用定位方法进行元素定位 el = self.locateElement(locate_type,value) # 执行输入操作 el.send_keys(data) # 获取指定元素的文本内容 def get_text(self, locate_type, value): # 调用定位方法进行元素定位 el = self.locateElement(locate_type, value) return el.text # 获取指定元素的属性值 def get_attr(self, locate_type, value, data): # 调用定位方法进行元素定位 el = self.locateElement(locate_type, value) return el.get_attribute(data) # 收尾清理方法 def __del__(self): time.sleep(3) self.driver.quit() if __name__ == '__main__': pass
2. Business-Login.py(后面会用到)
下面加了time.sleep()。因为后面案例2,3个测试用例,有2个都报错说没有定位到元素。因为网络太慢了,所以就加了延迟时间就可以了。
# 导入selenium封装类 import sys sys.path.append("..") from Commonlib.Commonlib import Commonshare import time class Login(Commonshare): def login(self,user,pwd): self.open_url('http://www.yhd.com/') self.click('class','hd_login_link') time.sleep(2) self.input_data('id','un',user) time.sleep(2) self.input_data('id','pwd',pwd) time.sleep(2) self.click('id','login_button') if __name__ == '__main__': log = Login() log.login('hack_ai_buster','1qaz2wsx#EDC')
案例1:登陆1号店,简单调用。
Testcase-testcase.py
import sys sys.path.append("..") from Business.Login import Login import unittest class Test(unittest.TestCase): def setUp(self): print('hello') def tearDown(self): print('bye') # 定义正确登陆的测试用例 # def test_001(self): # log = Login() # # 用账号密码登录 # log.login('18001225175','zyc123') # # 获取登录之后的用户名 # data = log.get_text('class','hd_login_name') # # 断言,判断登录后的用户名是否和预期用户名相同 # self.assertEqual('1800*****75@phone',data) # 账号密码都不输入,直接登录 def test_002(self): log = Login() # 用账号密码登录 log.login('', '') # 获取登录之后的用户名 data = log.get_text('id','error_tips') # 断言,判断登录后的用户名是否和预期用户名相同 self.assertEqual('请输入账号和密码',data) # 只输入账号不输入密码,直接登录 def test_003(self): log = Login() # 用账号密码登录 log.login('sdfsdadfa', '') # 获取登录之后的用户名 data = log.get_text('id', 'error_tips') # 断言,判断登录后的用户名是否和预期用户名相同 self.assertEqual('请输入密码', data) # 只输入账号不输入密码,直接登录 def test_004(self): log = Login() # 用账号密码登录 log.login('sdfsdadfa', '') # 获取登录之后的用户名 data = log.get_text('id', 'error_tips') # 断言,判断登录后的用户名是否和预期用户名相同 self.assertEqual('请输入密码itcast', data) if __name__ == '__main__': unittest.main()
注意:为了让后面的案例能够轻松的完成测试。test_001(正确的账号和密码)我注销了,后面的案例都不用这个,因为正确的账号密码输入,会有动态的拖图验证。有的时候弄不好,结果就不对。而且,不在空白处点,会只运行案例一,然后会报一个找不到句柄的错。为了引起不要的麻烦,运行后面三个案例就行。
如果想要运行test_001的代码,(正确的账号和密码)可以加time时间延长:
# 定义正确登陆的测试用例 def test_001(self): log = Login() # 用账号密码登录 time.sleep(2) log.login('18001225175','zyc123') # 获取登录之后的用户名 time.sleep(10) data = log.get_text('class','hd_login_name') # 断言,判断登录后的用户名是否和预期用户名相同 time.sleep(2) self.assertEqual('1800*****75@phone',data)
结果是:一个测试用例失败,三个测试用例通过。这是对的。
案例2:登陆1号店,测试套件调用。
Testcase-testsuit.py
import unittest import sys sys.path.append("..") from Testcase.testcase import Test # 导入HtmlTextRunner,用于生成html的测试报告 from Commonlib.HTMLTestRunner import HTMLTestRunner class SuitTest(unittest.TestCase): def test_suit(self): case_list = ['test_002','test_003','test_004'] # 创建测试套件 mysuit = unittest.TestSuite() # 循环将测试用例放到测试套件中 for case in case_list: mysuit.addTest(Test(case)) # 创建测试运行器,设置为每一个测试用例生成测试报告,运行测试套件中的测试用例 unittest.TextTestRunner(verbosity=2).run(mysuit) if __name__ == '__main__': unittest.main()
下面为什么总的是4个?因为Testcase-testsuit.py本身也算一个测试用例,所以是4个。
下面为什么只有3个测试用例结果?因为unittest.TextTestRunner(verbosity=2).run(mysuit)运行的是mysuit,所以具体的就mysiut定义的3个。
案例3:登陆1号店。
Testcase-testsuit2.py
import unittest import sys sys.path.append("..") from Testcase.testcase import Test # 导入HtmlTextRunner,用于生成html的测试报告 from Commonlib.HTMLTestRunner import HTMLTestRunner class SuitTest(unittest.TestCase): def test_suit(self): case_list = ['test_002','test_003','test_004'] # 创建测试套件 mysuit = unittest.TestSuite() # 循环将测试用例放到测试套件中 for case in case_list: mysuit.addTest(Test(case)) # 创建测试运行器,设置为每一个测试用例生成测试报告,运行测试套件中的测试用例 # unittest.TextTestRunner(verbosity=2).run(mysuit) # 生成html测试报告 with open('report.html','wb')as f: HTMLTestRunner( stream=f, # 相当于f.write(报告) title='第一个测试报告', description='it黑马第一个测试报告', verbosity=2 # 为每个测试用例生成测试报告 ).run(mysuit) if __name__ == '__main__': unittest.main()
生成report.html测试报告。可以在目录双击打开,也可以在pycharm中点击右上的浏览器图标。
可以看到下面有3个测试用例,一个失败,两个通过。
可以看到失败的一个测试用例具体错误的地方:
期待:请输入密码itcast 结果:请输入密码 ( 因为是不符的,所以失败。)
附:Commonlib-HTMLTestRunner.py(有点长哦)
https://www.cnblogs.com/zhangyangcheng/diary/2020/03/19/12523394.html