• python单元测试框架(继承、unittest参数化、断言、测试报告)


    一、继承

    继承能解决什么问题?

    unittest每个模块都要用到前提条件以及清理,如果有上百个模块,我们要改域名和浏览器,就会工作量很大特别麻烦,这时我们可以用继承的思想只用改一次

    我们可以将前提和清理提出来单独放到一个文件里,具体代码如下

    1. from selenium import webdriver
    2. import unittest
    3. class Init(unittest.TestCase):
    4. @classmethod
    5. def setUpClass(cls) -> None:
    6. cls.driver=webdriver.Chrome()
    7. cls.driver.maximize_window()
    8. cls.driver.get('http://www.baidu.com')
    9. cls.driver.implicitly_wait(30)
    10. @classmethod
    11. def tearDownClass(cls) -> None:
    12. cls.driver.quit()

    然后我们写测试用例的时候可以继承它,具体代码如下

    1. from selenium import webdriver
    2. import unittest
    3. from 单元测试框架.test.init import Init
    4. class BaiduTest(Init):
    5. def test_baidu_title(self):
    6. '''百度测试:验证百度首页的title'''
    7. # assert self.driver.title=='百度一下,你就知道'
    8. self.assertEqual(self.driver.title,'百度一下,你就知道')
    9. def test_baidu_url(self):
    10. '''百度测试:验证百度首页的url'''
    11. assert self.driver.current_url=='https://www.baidu.com/'
    12. def test_baidu_video(self):
    13. '''百度测试:验证点击视频后跳转到视频的页面'''
    14. nowhandler=self.driver.current_window_handle
    15. self.driver.find_element_by_link_text('视频').click()
    16. allhandlers=self.driver.window_handles
    17. for handler in allhandlers:
    18. if handler!=nowhandler:
    19. self.driver.switch_to.window(handler)
    20. self.assertTrue(self.driver.current_url,'https://haokan.baidu.com/?sfrom=baidu-top')
    21. self.driver.close()
    22. self.driver.switch_to.window(nowhandler)
    23. def test_baidu_map(self):
    24. '''百度测试:验证点击地图后跳转到地图的页面'''
    25. nowhandler=self.driver.current_window_handle
    26. self.driver.find_element_by_link_text('地图').click()
    27. allhandlers=self.driver.window_handles
    28. for handler in allhandlers:
    29. if handler!=nowhandler:
    30. self.driver.switch_to.window(handler)
    31. self.assertTrue(self.driver.current_url.startswith('https://map.baidu'))
    32. self.driver.close()
    33. self.driver.switch_to.window(nowhandler)
    34. if __name__ == '__main__':
    35. unittest.main()

    二、参数化

    unittest测试框架中,参数化使用的库为:parameterized 安装方式为:pip3 install parameterized

    参数化

    我们把相同的测试步骤,应用于不同的测试场景,那么我们就可以使用参数化了

    可以解决的问题是可以使用少量的测试代码,来覆盖更多的测试场景

    例如:我们测一下sina邮箱的登录模块,代码如下:

    1. from selenium import webdriver
    2. import unittest
    3. import time as t
    4. class BaiduTest(unittest.TestCase):
    5. def setUp(self) -> None: #前提
    6. self.driver=webdriver.Chrome()
    7. self.driver.get('https://mail.sina.com.cn/')
    8. self.driver.maximize_window()
    9. self.driver.implicitly_wait(30)
    10. def tearDown(self) -> None: #清理
    11. self.driver.quit()
    12. def test_sina_null(self):
    13. '''sina邮箱验证:登录账户为空'''
    14. self.driver.find_element_by_class_name('loginBtn').click()
    15. divText=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]')
    16. self.assertEqual(divText.text,'请输入邮箱名')
    17. def test_sina_email_format(self):
    18. '''sina邮箱验证:登录邮箱格式不正确'''
    19. self.driver.find_element_by_id('freename').send_keys('qwert')
    20. self.driver.find_element_by_class_name('loginBtn').click()
    21. divText=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]')
    22. self.assertEqual(divText.text,'您输入的邮箱名格式不正确')
    23. def test_sina_username_error(self):
    24. '''sina邮箱验证:登录账户不匹配'''
    25. self.driver.find_element_by_id('freename').send_keys('asdf@sina.com')
    26. self.driver.find_element_by_id('freepassword').send_keys('asdfg')
    27. self.driver.find_element_by_class_name('loginBtn').click()
    28. t.sleep(3)
    29. divText=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]')
    30. self.assertEqual(divText.text,'登录名或密码错误')
    31. if __name__ == '__main__':
    32. unittest.main()

    由于登录模块主要是⽤户名和密码的input表单的验证以及错误信息的验证,我们可以把用户名、密码、错误信息的验证参数化,具体实现的代码如下:

    1. from selenium import webdriver
    2. import unittest
    3. import time as t
    4. from parameterized import parameterized,param
    5. class BaiduTest(unittest.TestCase):
    6. def setUp(self) -> None: #前提
    7. self.driver=webdriver.Chrome()
    8. self.driver.get('https://mail.sina.com.cn/')
    9. self.driver.maximize_window()
    10. self.driver.implicitly_wait(30)
    11. def tearDown(self) -> None: #清理
    12. self.driver.quit()
    13. @parameterized.expand([
    14. param('','','请输入邮箱名'),
    15. param('wertasd', 'asdf', '您输入的邮箱名格式不正确'),
    16. param('wertasd@sina.cn', 'asdf', '登录名或密码错误')
    17. ])
    18. def test_sina_login(self,username,password,result):
    19. self.driver.find_element_by_id('freename').send_keys(username)
    20. t.sleep(3)
    21. self.driver.find_element_by_id('freepassword').send_keys(password)
    22. t.sleep(3)
    23. self.driver.find_element_by_class_name('loginBtn').click()
    24. t.sleep(3)
    25. divText=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]')
    26. self.assertEqual(divText.text,result)

    三、断言

    assertEqual

    assertEqual()是验证两个值相等,值的是数据类型与内容也是相等的,⻅案例代码:

    1. from selenium import webdriver
    2. import unittest
    3. class BaiduTest(unittest.TestCase):
    4. def setUp(self) -> None:
    5. self.driver=webdriver.Chrome()
    6. self.driver.get('http://www.baidu.com')
    7. self.driver.maximize_window()
    8. self.driver.implicitly_wait(30)
    9. def tearDown(self) -> None:
    10. self.driver.quit()
    11. def test_baidu_title(self):
    12. '''百度测试:验证百度首页的title'''
    13. # assert self.driver.title=='百度一下,你就知道'
    14. self.assertEqual(self.driver.title,'百度一下,你就知道')

    assertTrue

    返回的是bool类型,也就是对被测试的对象进⾏验证,如果返回的是boolean类型并且是true,那么结果验证通过,那么⽅法assertFlase()验证的是被测试对象返回的内容是false,⻅案例代码:

    1. from selenium import webdriver
    2. import unittest
    3. import time as t
    4. class BaiduTest(unittest.TestCase):
    5. def setUp(self) -> None: #前提
    6. self.driver=webdriver.Chrome()
    7. self.driver.get('https://mail.sina.com.cn/')
    8. self.driver.maximize_window()
    9. self.driver.implicitly_wait(30)
    10. def tearDown(self) -> None: #清理
    11. self.driver.quit()
    12. def test_sina_isLogin(self):
    13. '''sina邮箱验证,判断自动登录是否勾选'''
    14. isLogin=self.driver.find_element_by_id('store1')
    15. self.assertTrue(isLogin.is_selected())

    assertIn

    assertIn()值的是⼀个值是否包含在另外⼀个值⾥⾯,在这⾥特别的强调⼀下,在assertIn()的⽅法⾥⾯,有两个参数,那么值的包含其实就是第⼆个实际参数包含第⼀个实际参数。与之相反的⽅法是assergNotIn(),⻅案例代码:

    1. import unittest
    2. from selenium import webdriver
    3. class UiTest(unittest.TestCase):
    4. def setUp(self) -> None:
    5. self.driver=webdriver.Chrome()
    6. self.driver.maximize_window()
    7. self.driver.get('http://www.baidu.com')
    8. self.driver.implicitly_wait(30)
    9. def tearDown(self) -> None:
    10. self.driver.quit()
    11. def test_baidu_title_001(self):
    12. self.assertIn('百度',self.driver.title)
    13. def test_baidu_title_002(self):
    14. self.assertIn('百度⼀下,你就知道',self.driver.title)
    15. if __name__ == '__main__':
    16. unittest.main()

    四、测试报告

    在unittest的框架中,⽣成测试报告需要使⽤到HTMLTestRunner

    1. import unittest
    2. import os
    3. from 单元测试框架.HTMLTestRunner import HTMLTestRunner #从HTMLTestRunner模块调用HTMLTestRunner类
    4. def getTests():
    5. '''加载所有的测试模块'''
    6. suite=unittest.TestLoader().discover(
    7. #找到被执行模块的路径
    8. start_dir=os.path.dirname(__file__),
    9. #加载路径下所有以test_开头的测试模块的文件
    10. pattern='test_*.py' #正则表达式
    11. )
    12. return suite
    13. def runSuite():
    14. unittest.TextTestRunner().run(getTests())
    15. def base_dir():
    16. return os.path.dirname(os.path.dirname(__file__))#获取当前目录的上级目录
    17. def run():
    18. fp=open(os.path.join(base_dir(),'report','report.html'),'wb')#拼接report.html的路径 wb 二进制的方式写入
    19. runner=HTMLTestRunner(
    20. stream=fp, #流 执行一个写入一个
    21. title='UI自动化测试报告',
    22. description=''
    23. )
    24. runner.run(getTests())
    25. if __name__ == '__main__':
    26. run()

    怎么解决每次生成的测试报告不覆盖之前的测试报告,同时被保留:

    解决方法:引入时间库获取时间戳

    代码如下:

    1. import time
    2. import unittest
    3. import os
    4. from HTMLTestRunner import HTMLTestRunner
    5. def getTests():
    6. '''加载所有的测试模块'''
    7. suite=unittest.TestLoader().discover(
    8. #找到被执行模块的路径
    9. start_dir=os.path.dirname(__file__),
    10. #加载路径下所有以test_开头的测试模块的文件
    11. pattern='test_*.py' #正则表达式
    12. )
    13. return suite
    14. def getNowTime():
    15. return time.strftime('%y-%m-%d %H-%M-%S',time.localtime(time.time()))
    16. def base_dir():
    17. return os.path.dirname(os.path.dirname(__file__))
    18. def run():
    19. fp=open(os.path.join(base_dir(),'report',getNowTime()+'report.html'),'wb')
    20. runner=HTMLTestRunner(
    21. stream=fp,
    22. title='UI自动化测试报告',
    23. description=''
    24. )
    25. runner.run(getTests())
    26. if __name__ == '__main__':
    27. run()

    这样每次执行的都会生成一个测试报告:

    最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

    在这里插入图片描述

    这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!   

  • 相关阅读:
    一条SQL的执行原理
    Linux下修改可执行程序或者库的动态链接库的路径
    入门机器学习落地AI量化的最佳路径:类kaggle的算法竞赛
    数字孪生关键技术及标准
    eshop(商城管理系统)MySQL源码
    动态sql和分页
    设计行业中如何保证图纸设计稿在数据传输中不会泄密
    (41)STM32——外部SRAM实验笔记
    jmeter理论
    [js电子榨菜]事件传递机制 event propogate
  • 原文地址:https://blog.csdn.net/qq_48811377/article/details/133961582