• unittest单元测试框架使用


    什么是unittest
    这里我们将要用的unittest是python的单元测试框架,它的官网是 25.3. unittest — Unit testing framework — Python 2.7.18 documentation,在这里我们可以得到全面的信息。

    当我们写的用例越来越多时,我们就需要考虑用例编写的规范与组织,以便于后期的维护,而unittest正是这样一款工具。我们这里用一个示例来展示用unittest脚本是什么样子的

    1. 1 # -*- coding: utf-8 -*-
    2. 2 from selenium import webdriver
    3. 3 from selenium.webdriver.common.by import By
    4. 4 from selenium.webdriver.common.keys import Keys
    5. 5 from selenium.webdriver.support.ui import Select
    6. 6 from selenium.common.exceptions import NoSuchElementException
    7. 7 from selenium.common.exceptions import NoAlertPresentException
    8. 8 #导入unittest包
    9. 9 import unittest, time, re
    10. 10
    11. 11 #SearchTest类继承自unittest.TestCase,表明这是一个测试案例
    12. 12 class SearchTest(unittest.TestCase):
    13. 13 #setUp用于初始化工作
    14. 14 def setUp(self):
    15. 15 self.driver = webdriver.Firefox()
    16. 16 self.driver.implicitly_wait(30)
    17. 17 self.base_url = "https://www.baidu.com/"
    18. 18 self.verificationErrors = []
    19. 19 self.accept_next_alert = True
    20. 20
    21. 21 #以test开头的是我们的测试脚本
    22. 22 def test_search(self):
    23. 23 driver = self.driver
    24. 24 driver.get(self.base_url + "/")
    25. 25 driver.find_element_by_id("kw").click()
    26. 26 driver.find_element_by_id("kw").clear()
    27. 27 driver.find_element_by_id("kw").send_keys("selenium2")
    28. 28 driver.find_element_by_id("su").click()
    29. 29
    30. 30 def is_element_present(self, how, what):
    31. 31 try: self.driver.find_element(by=how, value=what)
    32. 32 except NoSuchElementException as e: return False
    33. 33 return True
    34. 34
    35. 35 def is_alert_present(self):
    36. 36 try: self.driver.switch_to_alert()
    37. 37 except NoAlertPresentException as e: return False
    38. 38 return True
    39. 39
    40. 40 def close_alert_and_get_its_text(self):
    41. 41 try:
    42. 42 alert = self.driver.switch_to_alert()
    43. 43 alert_text = alert.text
    44. 44 if self.accept_next_alert:
    45. 45 alert.accept()
    46. 46 else:
    47. 47 alert.dismiss()
    48. 48 return alert_text
    49. 49 finally: self.accept_next_alert = True
    50. 50
    51. 51 #在每个测试方法后执行,完成清理工作
    52. 52 def tearDown(self):
    53. 53 self.driver.quit()
    54. 54 self.assertEqual([], self.verificationErrors)
    55. 55
    56. 56 #整个测试过程集中在unittest的main()模块中,其默认执行以test开头的方法
    57. 57 if __name__ == "__main__":
    58. 58 unittest.main()

    通过这个我们大概对unittest有个直观的了解了。unittest.main():使用它可以将一个单元测试模块变为可直接运行的测试脚本,main()方法使用TestLoader类来搜索所有包含在该模块中以“test”命名开头的测试方法,并自动执行。执行方法的默认顺序是:根据ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z。所以以A开头的测试用例方法会优先执行,以a开头会后执行。

    unittest中的概念
    TestCase
    一个Testcase的实例就是一个测试用例,测试用例就是一个完整的测试流程,包括初始化setUp、运行run、测试后的还原tearDown。unittest.TestCase类,所有测试用例类继承的基本类。此类提供了很多assert方法用于检查比较,部分如下:

    多数方法都可以见其名知其意,使用的门槛很低。

    TestSuite
    对一个功能的测试往往需要多测试用例的,可以把多的测试用例集合在一起执行,这就是TestSuite的概念。常用addTest()方法将一个测试用例添加到测试套件中。

    TextTestRunner
    是用来执行测试用例的,其中的run(test)用来执行TestSuite/TestCase。测试的结果会保存在TextTestResult实例中。

    TestFixture
    测试准备前要做的工作和测试执行完后要做的工作.包括setUp()和tearDown()。通过覆盖TestCase的setUp和tearDown来实现。

    知道了这几个主要的概念,我们就可以把上面的脚本中的最后一行unittest.main(),改为以下代码:

    1. 1 #构造测试套件
    2. 2 suite = unittest.TestSuite()
    3. 3 suite.addTest(SearchTest("test_search"))
    4. 4 #执行测试
    5. 5 runner = unittest.TextTestRunner()
    6. 6 runner.run(suite)

    执行之后发现和之前用unittest.main()的结果一样。

    用例组织
    这里我们假设,脚本当中有多个TestCase如test_case1,test_case2…,那我们应该怎样去控制它们的执行顺序呢?

    执行测试用例方案一
    直接用

    unittest.main()
    执行,这里它搜索所有以test开头的测试用例方法,按照ASCII的顺序执行多个用例。

    执行测试用例方案二
    先实例化测试套件,将用例加载进去,再用TextTestRunner去执行用例:

    1. 1 suite=unittest.TestSuite()
    2. 2 suite.addTest(Test('test_case2'))
    3. 3 suite.addTest(Test('test_case1'))
    4. 4 runner=unittest.TextTestRunner()
    5. 5 runner.run(suite)

    执行的顺序是用例的加载顺序,比如这里是先执行2后执行1。

    执行测试用例方案三

    在方案2中,如果我们有成百上千个用例的话,一个一个add进去,是不太现实的,那么我们可以用defaultTestLoader来加载:

    1. 1 test_dir = './'
    2. 2 discover = unittest.defaultTestLoader.discover(test_dir, pattern='*test.py')
    3. 3 runner = unittest.TextTestRunner()
    4. 4 runner.run(discover)

    这里用./指定了当前目录,指定了*test.py文件,对其当中的用例进行执行,顺序和方案一相同。

    如果这里指定的目录下面有多个经pattern匹配上的.py文件呢?调用discover方法,首先通过test_dir定义查找目录,如果文件名满足定义的pattern,那么我们要用for循环来找出所有被筛选出来的用例,并将其循环加到套件中,主要代码如下:

    1. 1 for test_suite in discover:
    2. 2 for test_case in test_suite:
    3. 3 test_unit.addTests(test_case)

    由上面组织用例的方式我们可以知道,在实际的测试用脚本开发中,我们可以在目录下创建xx.py的文件,当用例稳定运行后,可以修改成test_xx.py,以便于添加到测试套件中。注意,文件名的匹配规则,我们可以随便由pattern参数定义。

    如果要执行多级目录结构的用例呢?要想被discover读取执行,我们要在目录下加_ init _.py文件

    一个例子
    下面简单的介绍一个用unittest组织的用例结构,先建立D:\Test_Project目录,下面放上test_case和test_report来分别存放用例和报告。

    编写测试用例
    在test_case下面编写用例,如下简单的示范了在百度上搜索关键字和点击设置的操作:

    1. 1 文件名为:test_baidu.py
    2. 2
    3. 3 # -*- coding: utf-8 -*-
    4. 4 from selenium import webdriver
    5. 5 import unittest, time, re
    6. 6
    7. 7 class MyTest(unittest.TestCase):
    8. 8
    9. 9 def setUp(self):
    10. 10 self.driver = webdriver.Firefox()
    11. 11 self.driver.implicitly_wait(30)
    12. 12 self.base_url = "https://www.baidu.com"
    13. 13 self.accept_next_alert = True
    14. 14
    15. 15 def test_02baidu_search(self):
    16. 16 u''' 测试百度搜索'''
    17. 17 driver = self.driver
    18. 18 driver.get(self.base_url + "/")
    19. 19 driver.find_element_by_id("kw").click()
    20. 20 driver.find_element_by_id("kw").clear()
    21. 21 driver.find_element_by_id("kw").send_keys("selenium-test")
    22. 22 driver.find_element_by_id("su").click()
    23. 23 print("test_baidu__test_02baidu_search")
    24. 24
    25. 25 def test_01baidu_setting(self):
    26. 26 u''' 测试百度首页设置 '''
    27. 27 driver = self.driver
    28. 28 driver.get(self.base_url + "/")
    29. 29 driver.find_element_by_css_selector("div#u1 a.pf").click()
    30. 30 driver.find_element_by_class_name("setpref").click()
    31. 31 driver.find_element_by_css_selector("div#gxszButton>a.prefpanelgo").click()
    32. 32 driver.switch_to_alert().accept()
    33. 33 print("test_baidu__test_01baidu_setting")
    34. 34
    35. 35 def tearDown(self):
    36. 36 self.driver.close()
    37. 37
    38. 38 #从all_test中调用时,可以不要这个
    39. 39 if __name__ == "__main__":
    40. 40 unittest.main()

    为了显示出组织测试用例的效果,我们将此文件再复制一份,把文件名和方法名等修改一下:

    1. 1 文件名为:test_baidu2.py
    2. 2
    3. 3 # -*- coding: utf-8 -*-
    4. 4 from selenium import webdriver
    5. 5 import unittest, time, re
    6. 6
    7. 7 class MyTest(unittest.TestCase):
    8. 8 u''' 测试baidu的第二个用例'''
    9. 9 def setUp(self):
    10. 10 self.driver = webdriver.Firefox()
    11. 11 self.driver.implicitly_wait(30)
    12. 12 self.base_url = "https://www.baidu.com"
    13. 13 self.accept_next_alert = True
    14. 14
    15. 15 def test_02baidu_search(self):
    16. 16 u''' 测试baidu的第二个用例的test_02baidu_search'''
    17. 17 driver = self.driver
    18. 18 driver.get(self.base_url + "/")
    19. 19 driver.find_element_by_id("kw").click()
    20. 20 driver.find_element_by_id("kw").clear()
    21. 21 driver.find_element_by_id("kw").send_keys("selenium-test")
    22. 22 driver.find_element_by_id("su").click()
    23. 23 print("test_baidu2__test_02baidu_search")
    24. 24
    25. 25
    26. 26 def test_01baidu_setting(self):
    27. 27 u''' 测试baidu的第二个用例的test_01baidu_setting'''
    28. 28 driver = self.driver
    29. 29 driver.get(self.base_url + "/")
    30. 30 driver.find_element_by_css_selector("div#u1 a.pf").click()
    31. 31 driver.find_element_by_class_name("setpref").click() driver.find_element_by_css_selector("div#gxszButton>a.prefpanelgo").click()
    32. 32 driver.switch_to_alert().accept()
    33. 33 print("test_baidu2__test_01baidu_setting")
    34. 34
    35. 35 def tearDown(self):
    36. 36 self.driver.close()
    37. 37
    38. 38 if __name__ == "__main__":
    39. 39 unittest.main()
    美化报告样式和发送结果邮件

    上面我们写了 两个测试用例作为示例,我们也可以添加更多的进去。接着我们使用HTMLTestRunner这个开源模块来美化测试报告。然后,我们可以在代码中写上运行完成之后自动发送测试邮件出来,便于我们查看。请参看以下代码:

    1. 1 #coding=utf-8
    2. 2 import unittest
    3. 3 import smtplib
    4. 4 from email.mime.text import MIMEText
    5. 5 from email.header import Header
    6. 6 import time
    7. 7 import HTMLTestRunner
    8. 8 from email.mime.application import MIMEApplication
    9. 9
    10. 10 #---发送邮件---
    11. 11 def send_email(report_file):
    12. 12 sender = "XXXXXX@qq.com"
    13. 13 receiver = "XXXXXX@qq.com"
    14. 14 smtpserver = "smtp.qq.com"
    15. 15 #发送邮箱的账号密码,此处使用的是qq邮箱和第三方登录的授权码
    16. 16 username = "XXXXXX@qq.com"
    17. 17 password = "gfomcomojtuudijc"
    18. 18
    19. 19 #定义邮件正文
    20. 20 file = open(report_file,"rb")
    21. 21 mail_body = file.read()
    22. 22 file.close()
    23. 23
    24. 24 msg = MIMEText(mail_body, _subtype="html", _charset="utf-8")
    25. 25 msg["Subject"] = u"自动化测试报告"
    26. 26
    27. 27 smtp = smtplib.SMTP_SSL("smtp.qq.com")
    28. 28 smtp.login(username, password)
    29. 29 smtp.sendmail(sender, receiver, msg.as_string())
    30. 30 smtp.quit()
    31. 31 print("Email has send out !")
    32. 32
    33. 33 #---将用例添加到测试套件---
    34. 34 def creatsuite():
    35. 35 testunit=unittest.TestSuite()
    36. 36 test_dir = "D:\\Test_Project\\test_case"
    37. 37 discover = unittest.defaultTestLoader.discover(test_dir, pattern="test*.py",
    38. 38 top_level_dir = None)
    39. 39 for test_suite in discover:
    40. 40 for test_case in test_suite:
    41. 41 testunit.addTest(test_case)
    42. 42 print (testunit)
    43. 43 return testunit
    44. 44
    45. 45 if __name__ == "__main__":
    46. 46 current_time = time.strftime("%Y-%m-%d-%H-%M")
    47. 47 report_dir = "D:\\Test_Project\\test_report\\"
    48. 48 report_file = report_dir + current_time + "-Test_Result.html"
    49. 49 report_stream = open(report_file, "wb")
    50. 50 # runner = unittest.TextTestRunner()
    51. 51 # 注意HTMLTestRunner只支持python2
    52. 52 runner = HTMLTestRunner.HTMLTestRunner(stream=report_stream,title=u"自动化测试报告", description=u"用例执行情况如下:")
    53. 53 runner.run(creatsuite())
    54. 54 report_stream.close()
    55. 55 send_email(report_file)

    在上面的代码中我们使用了runner = HTMLTestRunner.HTMLTestRunner()方法来代替runner = unittest.TextTestRunner(),是为了使用HTMLTestRunner这个模块来美化和输出美观的报告。然后调用方法来发送邮件。运行此文件后,可以得到以下输出的报告:

    可以看见使用这个可以清晰的看到用例的执行情况, 也便于查看失败用例的原因去调试它,同时在们输入的收件箱也会收到一份通知邮件,我们可以将此输出报告添加到正文或附件中,以便于查看

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

    文档获取方式:

    这份文档,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!

    以上均可以分享,只需要你搜索vx公众号:程序员雨果,即可免费领取

  • 相关阅读:
    加速释放传统企业业务潜力,S2B2B商城建设方案引领电商模式新风向
    接口请求加签名
    SpringBoot拉取高德天气预报数据
    Python实现猎人猎物优化算法(HPO)优化BP神经网络分类模型(BP神经网络分类算法)项目实战
    Go pprof 认知到实践
    【云原生之Docker实战】部署docker管理平台shipyard
    算法进阶系列1 空间搜索 GeoHash 算法
    贯头山酒——中华酒文化的源头之一
    基于Javamail的邮件收发系统免费系统+LW
    数据库防火墙技术展望【终章】
  • 原文地址:https://blog.csdn.net/2301_77645750/article/details/133362358