Python单元测试框架(unittest,固件,参数化)
一、Python测试框架
在Python语⾔中应⽤最⼴泛的单元测试框架是unittest和pytest,unittest属于标准库,只要安装了Python解释器后就可以直接导⼊使⽤了,pytest是第三⽅的库,需要单独的安装。
1、⽩盒测试原理
在软件架构的层⾯来说,测试最核⼼的步骤就是在软件开发过程中。就软件本身⽽⾔,软件的⾏为或者功能是软件细节实现的产物,这些最终是交付给⽤户的东⻄。所以在早期执⾏测试的系统有可能是⼀个可测试和健壮的系统,它会带来为⽤户提供的功能往往是让⼈满意的结果。因此给予这样的⻆度,开始执⾏测试的最佳⽅法是来⾃源代码,也就是软件编写的地⽅以及开发⼈员。由于源代码是对开发⼈员是可⻅的,这样的⼀个测试过程我们可以称为白盒测试。
2、unittest实战
- 测试⽤例:测试类继承unittest模块中的TestCase类后,依据继承的这个类来设置⼀个新的测试⽤例类和测试⽅法。
- 测试固件:测试固件表示⼀个测试⽤例或者多个测试以及清理⼯作所需要的设置或者准备。
- 测试套件:测试套件顾名思义就是相关测试⽤例的集合。在unittest中主要通过TestSuite类提供对测试套件的⽀持。
- 测试运⾏:管理和运⾏测试⽤例的对象。
- 测试断⾔:对所测试的对象依据返回的实际结果与期望结果进⾏断⾔校验
- 测试结果:测试结果类管理着测试结果的输出,测试结果呈现给最终的⽤户来反馈本次测试执⾏的结果信息。
3、unittest测试固件详解
在unittest中测试固件依据⽅法可以分为两种执⾏⽅式,⼀种是测试固件只执⾏⼀次,另外⼀种是测试固件每次都执⾏,下⾯依据具体的案例来讲解⼆者。(1)测试固件每次均执⾏(setUp tearDown 它的顺序为:测试固件-->测试⽤例,测试固件-->测试⽤例)
from selenium import webdriver import unittest class TestSina(unittest.TestCase): def setUp(self) -> None: self.driver=webdriver.Chrome() self.driver.maximize_window() self.driver.get('https://mail.sina.com.cn/') self.driver.implicitly_wait(30) def tearDown(self) -> None: self.driver.quit() def test_sina_001(self): isLogin=self.driver.find_element_by_id('store1') self.assertEqual(isLogin.is_selected(),True) def test_sina_002(self): self.driver.find_element_by_class_name('loginBtn').click() errorText=self.driver.find_element_by_xpath('/html/body/div[3]/div/div[2]/div/div/div[4]/div[1]/div[1]/div[1]/span[1]') # print(errorText.text) self.assertEqual(errorText.text,'请输入邮箱名') def test_sina_003(self): self.driver.find_element_by_id('freename').send_keys('15730996037') self.driver.find_element_by_class_name('loginBtn').click() aaText=self.driver.find_element_by_xpath('/html/body/div[3]/div/div[2]/div/div/div[4]/div[1]/div[1]/div[1]/span[2]') # print(aaText.text) self.assertEqual(aaText.text,'请输入密码') if __name__=='__main__': unittest.main(verbosity=2)
from selenium import webdriver import unittest """类测试固件执行一次""" class TestSina(unittest.TestCase): @classmethod def setUpClass(cls) -> None: cls.driver=webdriver.Chrome() cls.driver.maximize_window() cls.driver.get('https://mail.sina.com.cn/') cls.driver.implicitly_wait(30) @classmethod def tearDownClass(cls) -> None: cls.driver.quit() def test_sina_001(self): isLogin=self.driver.find_element_by_id('store1') self.assertEqual(isLogin.is_selected(),True) def test_sina_002(self): self.driver.find_element_by_class_name('loginBtn').click() errorText=self.driver.find_element_by_xpath('/html/body/div[3]/div/div[2]/div/div/div[4]/div[1]/div[1]/div[1]/span[1]') # print(errorText.text) self.assertEqual(errorText.text,'请输入邮箱名') def test_sina_003(self): nowHandle=self.driver.current_window_handle self.driver.find_element_by_link_text('注册') allHandles=self.driver.window_handles for handle in allHandles: if handle!=nowHandle: self.driver.switch_to.window(handle) self.assertEqual(self.driver.current_url,'register/regmail.php') self.driver.close() def test_sina_004(self): self.driver.find_element_by_id('freename').send_keys('15730996037') self.driver.find_element_by_class_name('loginBtn').click() aaText=self.driver.find_element_by_xpath('/html/body/div[3]/div/div[2]/div/div/div[4]/div[1]/div[1]/div[1]/span[2]') # print(aaText.text) self.assertEqual(aaText.text,'请输入密码') if __name__=='__main__': unittest.main(verbosity=2)
4、测试⽤例执⾏顺序详解
在unittest中,测试点的执⾏顺序是依据ascill码来执⾏的,也就是说根据ASCII码的顺序加载,数字与字⺟的顺序为:0-9,A-Z,a-z,所以以A开头的测试⽤例⽅法会优先执⾏,以a开头会后执⾏。也就是根据数字的⼤⼩从⼩到⼤执⾏的,切记数字的⼤⼩值的是不包含test,值的是test后⾯的测试点的数字⼤⼩。
5、编写测试⽤例注意事项
测试⽤例注意事项如下:
1、在⼀个测试类⾥⾯,每⼀个测试⽅法都是以test开头的,test不能是中间或者尾部,必须是开头,建议test_
2、每⼀个测试⽤例⽅法都应该有注释信息,这样在测试报告就会显示具体的测试点的检查点
3、在⾃动化测试中,每个测试⽤例都必须得有断⾔,⽆断⾔的⾃动化测试⽤例是⽆效的
4、最好⼀个测试⽤例⽅法对应⼀个业务测试点,不要多个业务检查点写⼀个测试⽤例
5、如果涉及到业务逻辑的处理,最好把业务逻辑的处理⽅法放在断⾔前⾯,这样做的⽬的是不要因为业务逻辑执⾏错误导致断⾔也是失败
6、测试⽤例名称最好规范,有约束
7、是否先写⾃动化测试的测试代码,在使⽤⾃动化测试⽅式写,本⼈觉得没必要,毕竟能够做⾃动化测试的都具备了功能测试的基本⽔平,所以没必要把⼀个业务的检查点写多次,浪费时间和⼈⼒成本。
6、分离测试套件
利⽤继承的思想分离出测试套件,测试类只需要继承分离的类就可以了
from selenium import webdriver import unittest """分离测试构件,用继承思想少写代码""" import time as t class Init(unittest.TestCase): def setUp(self) -> None: self.driver = webdriver.Chrome() self.driver.maximize_window() self.driver.get('https://mail.sina.com.cn/') self.driver.implicitly_wait(30) def tearDown(self) -> None: self.driver.quit() class TestSina(Init): def test_sina_001(self): isLogin=self.driver.find_element_by_id('store1') self.assertEqual(isLogin.is_selected(),True) def test_sina_002(self): self.driver.find_element_by_class_name('loginBtn').click() errorText=self.driver.find_element_by_xpath('/html/body/div[3]/div/div[2]/div/div/div[4]/div[1]/div[1]/div[1]/span[1]') # print(errorText.text) self.assertEqual(errorText.text,'请输入邮箱名') def test_sina_003(self): self.driver.find_element_by_id('freename').send_keys('15730996037') self.driver.find_element_by_class_name('loginBtn').click() aaText=self.driver.find_element_by_xpath('/html/body/div[3]/div/div[2]/div/div/div[4]/div[1]/div[1]/div[1]/span[2]') # print(aaText.text) self.assertEqual(aaText.text,'请输入密码') if __name__=='__main__': unittest.main(verbosity=2)
7、unittest的参数化
parameterized实战
在unittest的测试框架中,可以结合ddt的模块来达到参数化的应⽤,当然关于ddt库的应⽤在数据驱动⽅⾯有很详细的解释,这⾥就直接说另外的⼀个第三⽅的库parameterized,安装的命令为:pip3 install parameterized安装成功后,这⾥就以⼀个两个数相加的案例。
"""参数化""" import unittest from parameterized import parameterized,param from selenium import webdriver import time as t def add(a,b): return a+b class AddTest(unittest.TestCase): def setUp(self) -> None: pass def tearDown(self) -> None: pass @parameterized.expand([ param(1,1,2), param(2,2,4), param(1.0,1.0,2.0), param('hi','wuyikai','hiwuyikai') ]) def test_add(self,a,b,result): self.assertEqual(add(a,b),result) if __name__=='__main__': unittest.main(verbosity=2)
"""新浪邮箱参数化实战""" import unittest from parameterized import parameterized,param from selenium import webdriver import time as t class UITest(unittest.TestCase): def setUp(self) -> None: self.driver=webdriver.Chrome() self.driver.maximize_window() self.driver.get('https://mail.sina.com.cn/') self.driver.implicitly_wait(30) def tearDown(self) -> None: self.driver.quit() @parameterized.expand([ param('','','请输入邮箱名'), param('44556621114185632212vsv12@bvbs','asdfg','您输入的邮箱名格式不正确'), param('15730996037','asdfg','登录名或密码错误') ]) def test_sina_login(self,username,password,divText): self.driver.find_element_by_id('freename').send_keys(username) self.driver.find_element_by_id('freepassword').send_keys(password) self.driver.find_element_by_link_text('登录').click() t.sleep(3) errorText=self.driver.find_element_by_xpath('/html/body/div[3]/div/div[2]/div/div/div[4]/div[1]/div[1]/div[1]/span[1]') self.assertEqual(errorText.text,divText) if __name__=='__main__': unittest.main(verbosity=2)
"""网易邮箱参数化实战""" # import unittest # from parameterized import parameterized,param # from selenium import webdriver # import time as t # # class UITest(unittest.TestCase): # def setUp(self) -> None: # self.driver=webdriver.Chrome() # self.driver.maximize_window() # self.driver.get('https://mail.163.com/') # self.driver.implicitly_wait(30) # def tearDown(self) -> None: # self.driver.quit() # @parameterized.expand([ # param('','','请输入帐号'), # param('15730996037','','请输入密码'), # param('15730996037','asdfg','帐号或密码错误') # ]) # def test_wangyi_login(self,username,password,divText): # self.driver.switch_to.frame(0) # self.driver.find_element_by_name('email').send_keys(username) # self.driver.find_element_by_name('password').send_keys(password) # self.driver.find_element_by_id('dologin').click() # t.sleep(3) # errorText=self.driver.find_element_by_class_name('ferrorhead') # self.assertEqual(errorText.text,divText) # print(errorText.text) # # # # if __name__=='__main__': # unittest.main(verbosity=2
"""百度网盘参数化实战""" import unittest from parameterized import parameterized,param from selenium import webdriver import time as t class WPTest(unittest.TestCase): def setUp(self) -> None: self.driver=webdriver.Chrome() self.driver.maximize_window() self.driver.get('https://pan.baidu.com/') self.driver.implicitly_wait(30) def tearDown(self) -> None: self.driver.quit() @parameterized.expand([ param('','','请您输入手机/邮箱/用户名'), param('15564598498','','请您输入密码'), param('15730996037','asdfg','用户名或密码有误,请重新输入或找回密码') ]) def test_wangpan_login(self,username,password,divText): self.driver.find_element_by_name('userName').send_keys(username) self.driver.find_element_by_name('password').send_keys(password) self.driver.find_element_by_id('TANGRAM__PSP_4__submit').click() t.sleep(10) errorText=self.driver.find_element_by_id('TANGRAM__PSP_4__error') self.assertEqual(errorText.text,divText) print(errorText.text) if __name__ == '__main__': unittest.main(verbosity=2)