【测试开发】自动化测试selenium(三)——unittest框架解析

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: unittest框架解析批量执行脚本构建测试套件addTest() 的应用makeSuite()和TestLoader()的应用discover()的应用用例执行顺序忽略用例执行unittest断言HTML报告生成异常捕捉与错误截图

unittest框架解析


unittest 是python 的单元测试框架, 在python 的官方文档中,对unittest有详细的介绍,想更深一步研究的同学可以到https://www.python.org/doc/ 去了解。


unittest 单元测试提供了创建测试用例,测试套件以及批量执行的方案, unittest 在安装pyhton 以后就直接自带了,直接import unittest 就可以使用。


作为单元测试的框架, unittest 也是可以对程序最小模块的一种敏捷化的测试。在自动化测试中,我们虽然不需要做白盒测试,但是必须需要知道所使用语言的单元测试框架。利用单元测试框架,创建一个类,该类继承unittest的TestCase,这样可以把每个case看成是一个最小的单元, 由测试容器组织起来,到时候直接执行,同时引入测试报告。


unittest各组件关系为:


1.png


test fixture:测试固件,初始化和清理测试环境,比如创建临时的数据库,文件和目录等,其中 setUp() 和 setDown()是最常用的方法

test case:单元测试用例,TestCase 是编写单元测试用例最常用的类

test suite:测试套件,单元测试用例的集合,TestSuite 是最常用的类

test runner:执行单元测试

test report:生成测试报告


unittest和Junit的区别


22.png



测试固件简单来说:

3.png


import time
from selenium import webdriver
import unittest
class Test(unittest.TestCase):
    # Test继承自unittest.TestCase
    # 测试固件 setup和tearDown
    # 这里的self相当于是一个实例
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.url = "http://www.baidu.com/"
        self.driver.maximize_window()
    def tearDown(self):
        self.driver.quit()
    # 测试方法名必须要test_不然不执行
    def test_baidu(self):
        driver = self.driver
        driver.get(self.url)
        driver.find_element_by_id("kw").send_keys("kobe")
        driver.find_element_by_id("su").click()
        time.sleep(3)
    if __name__ == "__main__":
        unittest.main(2)
'''
可以增加verbosity参数,例如unittest.main(verbosity=2)
在主函数中,直接调用main() ,在main中加入verbosity=2 ,这样测试的结果就会显示的更加详细。
这里的verbosity 是一个选项, 表示测试结果的信息复杂度,有三个值:
0 ( 静默模式): 你只能获得总的测试用例数和总的结果比如总共100个失败,20 成功80
1 ( 默认模式): 非常类似静默模式只是在每个成功的用例前面有个“ . ” 每个失败的用例前面有个“F”
2 ( 详细模式): 测试结果会显示每个测试用例的所有相关的信息
'''


4.png


批量执行脚本


构建测试套件


完整的单元测试很少只执行一个测试用例,开发人员通常都需要编写多个测试用例才能对某一软件功能进行比较完整的测试,这些相关的测试用例称为一个测试用例集,在unittest中是用TestSuite 类来表示的。


假设我们已经编写了testbaidu1.py,testbaidu2.py两个文件,那么我们怎么同时执行这两个文件呢?


addTest() 的应用


当有多个或者几百测试用例的时候, 这样就需要一个测试容器( 测试套件) ,把测试用例放在该容器中进行执行,unittest 模块中提供了TestSuite 类来生成测试套件,使用该类的构造函数可以生成一个测试套件的实例,该类提供了addTest来把每个测试用例加入到测试套件中。

将testbaidu1.py、testbaidu2.py、runall.py放在同一个目录testcase中


runall.py内容如下


import time
# 导入test_baidu1,test_baidu2
import test_baidu1
import test_baidu2
import unittest
# 手工添加案例到套件,
def createsuite():
    suite = unittest.TestSuite()
    # 将测试用例加入到测试容器(套件)中
    suite.addTest(test_baidu1.Baidu1("test_baidu1"))
    suite.addTest(test_baidu2.Baidu2("test_baidu2"))
    return suite
if __name__ == "__main__":
    suite = createsuite()
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(suite)


5.png


上述做法有两个不方面的地方,阻碍脚本的快速执行,必须每次修改runall.py:

1)需要导入所有的py文件,比如import testbaidu1,每新增一个需要导入一个

2)addTest需要增加所有的testcase,如果一个py文件中有10个case,就需要增加10次


makeSuite()和TestLoader()的应用


在unittest 框架中提供了makeSuite() 的方法,makeSuite可以实现把测试用例类内所有的测试case组成的测试套件TestSuite ,unittest 调用makeSuite的时候,只需要把测试类名称传入即可。


TestLoader 用于创建类和模块的测试套件

一般的情况下,使TestLoader().loadTestsFromTestCase(TestClass)来加载测试类。


runall.py 内容如下


import time
# 导入test_baidu1,test_baidu2
import test_baidu1
import test_baidu2
import unittest
# 手工添加案例到套件,
def createsuite():
 suite = unittest.TestSuite()
 # 将测试用例加入到测试容器(套件)中
 suite.addTest(unittest.makeSuite(test_baidu1.Baidu1))
 suite.addTest(unittest.makeSuite(test_baidu2.Baidu2))
 return suite
'''
 suite1 = unittest.TestLoader().loadTestsFromTestCase(test_baidu1.Baidu1) 
 suite2 = unittest.TestLoader().loadTestsFromTestCase(test_baidu2.Baidu2) 
 suite = unittest.TestSuite([suite1, suite2])
 return suite
 '''
if __name__ == "__main__":
    suite = createsuite()
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(suite)


6.png


经过makeSuite()和TestLoader()的引入,我们不用一个py文件测试类,只需要导入一次即可。

那么能不能测试类也不用每次添加指定呢?


discover()的应用


discover 是通过递归的方式到其子目录中从指定的目录开始, 找到所有测试模块并返回一个包含它们对象的TestSuite ,然后进行加载与模式匹配唯一的测试文件,discover 参数分别为

discover(dir,pattern,top_level_dir=None)


runall.py—注意路径



# -*- coding: utf-8 -*-
import unittest,csv
import os,sys
import time
#手工添加案例到套件,
def createsuite():
discover=unittest.defaultTestLoader.discover('../test',pattern='test*.py',top_level_dir=None)
 print discover
 return discover
if __name__=="__main__":
 suite=createsuite()
 runner = unittest.TextTestRunner(verbosity=2)
 runner.run(suite)


用例执行顺序


unittest 框架默认加载测试用例的顺序是根据ASCII 码的顺序,数字与字母的顺序为: 09,AZ,a~z


所以, TestAdd 类会优先于TestBdd 类被发现, test_aaa() 方法会优先于test_ccc() 被执行。

对于测试目录与测试文件来说, unittest 框架同样是按照这个规则来加载测试用例。

addTest()方法按照增加顺序来执行。


忽略用例执行


@unittest.skip("skipping")

在测试方法前边加上这个注释就是忽略用例执行


unittest断言


自动化的测试中, 对于每个单独的case来说,一个case的执行结果中, 必然会有期望结果与实际结果, 来判断该case是通过还是失败, 在unittest 的库中提供了大量的实用方法来检查预期值与实际值, 来验证case的结果, 一般来说, 检查条件大体分为等价性, 逻辑比较以及其他, 如果给定的断言通过, 测试会继续执行到下一行的代码, 如果断言失败, 对应的case测试会立即停止或者生成错误信息( 一般打印错误信息即可) ,但是不要影响其他的case执行。


unittest 的单元测试库提供了标准的xUnit 断言方法。下面是一些常用的断言


7.png



import time
from selenium import webdriver
import unittest
class Baidu1(unittest.TestCase):
    # Test继承自unittest.TestCase
    # 测试固件 setup和tearDown
    # 这里的self相当于是一个实例
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.url = "http://www.baidu.com/"
        self.driver.maximize_window()
    def tearDown(self):
        self.driver.quit()
    # 测试方法名必须要test_不然不执行
    def test_baidu1(self):
        driver = self.driver
        driver.get(self.url)
        driver.find_element_by_id("kw").send_keys("kobe")
        driver.find_element_by_id("su").click()
        # 添加断言
        self.assertEqual("kobe", driver.find_element_by_link_text("科比·布莱恩特 - 百度百科").text,msg="kobe!=科比·布莱恩特 - 百度百科")
        time.sleep(3)
    if __name__ == "__main__":
        unittest.main(2)
'''
可以增加verbosity参数,例如unittest.main(verbosity=2)
在主函数中,直接调用main() ,在main中加入verbosity=2 ,这样测试的结果就会显示的更加详细。
这里的verbosity 是一个选项, 表示测试结果的信息复杂度,有三个值:
0 ( 静默模式): 你只能获得总的测试用例数和总的结果比如总共100个失败,20 成功80
1 ( 默认模式): 非常类似静默模式只是在每个成功的用例前面有个“ . ” 每个失败的用例前面有个“F”
2 ( 详细模式): 测试结果会显示每个测试用例的所有相关的信息
'''


8.png


可以通过IDE来添加断言:


9.png


HTML报告生成


脚本执行完毕之后,还需要看到HTML报告,下面我们就通过HTMLTestRunner.py 来生成测试报告。

HTMLTestRunner支持python2.7。python3可以参见以下网址里的代码,之间复制粘贴即可


https://blog.csdn.net/liubo37/article/details/105069609/


HTMLTestRunner.py 文件,下载地址:

http://tungwaiyip.info/software/HTMLTestRunner.html

下载后将其放在testcase目录中去或者放入…\Python27\Lib 目录下(windows)。


修改runall.py



# -*- coding: utf-8 -*-
import unittest,csv
import os,sys
import time
import HTMLTestRunner
#手工添加案例到套件,
def createsuite():
discover=unittest.defaultTestLoader.discover('../test',pattern='test*.py',top_level_dir=None)
 print discover
 return discover
 if __name__=="__main__":
 curpath=sys.path[0]
 #解决重复命名的问题
 now=time.strftime("%Y-%m-%d-%H %M %S",time.localtime(time.time()))
 # 当前路径下resulreport文件夹不存在的时候就创建一个
 if not os.path.exists(curpath+'/resultreport'):
 os.makedirs(curpath+'/resultreport')
 #文件名是路径加上文件的名称
 #准备HTML报告输出的文件
 filename=curpath+'/resultreport/'+now+'resultreport.html'
 #打开HTML文件,wb 以写的方式
 with open(filename,'wb') as fp:
 #出html报告,括号里的参数是HTML报告里的参数
 runner=HTMLTestRunner.HTMLTestRunner(stream=fp,title=u'测试报告',description=u'用例执行
情况',verbosity=2)
 suite=createsuite()
 runner.run(suite)

10.png


11.png


异常捕捉与错误截图


用例不可能每一次运行都成功,肯定运行时候有不成功的时候。如果可以捕捉到错误,并且把错误截图保存,这将是一个非常棒的功能,也会给我们错误定位带来方便。

例如编写一个截图函数,关键语句为driver.get_screenshot_as_file:


def savescreenshot(self,driver,file_name):
 if not os.path.exists('./image'):
 os.makedirs('./image')
 now=time.strftime("%Y%m%d-%H%M%S",time.localtime(time.time()))
 #截图保存
 driver.get_screenshot_as_file('./image/'+now+'-'+file_name)
 time.sleep(1)


一个引用例子:


# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re
import os
class Baidu1(unittest.TestCase):
#test fixture,初始化环境
 def setUp(self):
 self.driver = webdriver.Firefox()
 self.driver.implicitly_wait(30)
 self.base_url = "http://www.baidu.com/"
 self.verificationErrors = []
 self.accept_next_alert = True
 #测试用例,必须以test开头 
 def test_hao(self):
 driver = self.driver
 driver.get(self.base_url + "/")
 driver.find_element_by_link_text("hao123").click()
 time.sleep(2)
 try:
 self.assertEqual(u'hao_上网从这里开始', driver.title)
 except:
 self.savescreenshot(driver,'hao.png')
 #判断element是否存在,可删除 
 def is_element_present(self, how, what):
 try: self.driver.find_element(by=how, value=what)
 except NoSuchElementException as e: return False
 return True
 #判断alert是否存在,可删除 
 def is_alert_present(self):
 try: self.driver.switch_to_alert()
 except NoAlertPresentException as e: return False
 return True
 #关闭alert,可删除 
 def close_alert_and_get_its_text(self):
 try:
 alert = self.driver.switch_to_alert()
 alert_text = alert.text
 if self.accept_next_alert:
 alert.accept()
 else:
 alert.dismiss()
 return alert_text
 finally: self.accept_next_alert = True
 #test fixture,清除环境 
 def tearDown(self):
 self.driver.quit()
 self.assertEqual([], self.verificationErrors)
 def savescreenshot(self,driver,file_name):
 if not os.path.exists('./image'):
 os.makedirs('./image')
 now=time.strftime("%Y%m%d-%H%M%S",time.localtime(time.time()))
 #截图保存
 driver.get_screenshot_as_file('./image/'+now+'-'+file_name)
 time.sleep(1)
if __name__ == "__main__":
#执行用例
 unittest.main()
 '''
可以增加verbosity参数,例如unittest.main(verbosity=2)
在主函数中,直接调用main() ,在main中加入verbosity=2 ,这样测试的结果就会显示的更加详细。
这里的verbosity 是一个选项, 表示测试结果的信息复杂度,有三个值:
0 ( 静默模式): 你只能获得总的测试用例数和总的结果比如总共100个失败,20 成功80
1 ( 默认模式): 非常类似静默模式只是在每个成功的用例前面有个“ . ” 每个失败的用例前面有个“F”
2 ( 详细模式): 测试结果会显示每个测试用例的所有相关的信息
'''



相关文章
|
17天前
|
人工智能 搜索推荐 数据管理
探索软件测试中的自动化测试框架选择与优化策略
本文深入探讨了在现代软件开发流程中,如何根据项目特性、团队技能和长期维护需求,精准选择合适的自动化测试框架。
68 8
|
2天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
10天前
|
机器学习/深度学习 人工智能 jenkins
探索软件测试中的自动化与持续集成
【10月更文挑战第21天】 在软件开发的生命周期中,软件测试扮演着至关重要的角色。随着技术的进步和开发模式的转变,自动化测试和持续集成已经成为提高软件质量和效率的关键手段。本文将深入探讨自动化测试和持续集成的概念、实施策略以及它们如何相互配合以优化软件开发流程。我们将通过分析实际案例,展示这些技术如何在实际项目中发挥作用,以及面临的挑战和解决方案。此外,文章还将讨论未来趋势,包括人工智能在测试领域的应用前景。
57 17
|
22天前
|
Java 测试技术 API
探索软件测试中的自动化测试框架
本文深入探讨了自动化测试在软件开发中的重要性,并详细介绍了几种流行的自动化测试框架。通过比较它们的优缺点和适用场景,旨在为读者提供选择合适自动化测试工具的参考依据。
|
23天前
|
监控 数据管理 测试技术
API接口自动化测试深度解析与最佳实践指南
本文详细介绍了API接口自动化测试的重要性、核心概念及实施步骤,强调了从明确测试目标、选择合适工具、编写高质量测试用例到构建稳定测试环境、执行自动化测试、分析测试结果、回归测试及集成CI/CD流程的全过程,旨在为开发者提供一套全面的技术指南,确保API的高质量与稳定性。
|
23天前
|
数据管理 测试技术 持续交付
软件测试中的自动化测试策略与最佳实践
在当今快速迭代的软件开发环境中,自动化测试已成为确保软件质量和加速产品上市的关键手段。本文旨在探讨软件测试中的自动化测试策略,包括选择合适的自动化测试工具、构建有效的自动化测试框架以及实施持续集成和持续部署(CI/CD)。通过分析自动化测试的最佳实践,本文为软件开发团队提供了一系列实用的指南,以优化测试流程、提高测试效率并减少人为错误。
57 4
|
23天前
|
jenkins 测试技术 持续交付
软件测试中的自动化与持续集成
在现代软件开发过程中,自动化测试和持续集成已成为不可或缺的组成部分。本文将深入探讨自动化测试和持续集成的重要性、优势以及如何有效实施它们以提升软件质量和开发效率。通过具体案例分析,我们将展示这些技术如何在实际项目中发挥作用,并讨论其面临的挑战及应对策略。
47 3
|
20天前
|
监控 搜索推荐 测试技术
电商API的测试与用途:深度解析与实践
在电子商务蓬勃发展的今天,电商API成为连接电商平台、商家、消费者和第三方开发者的重要桥梁。本文深入探讨了电商API的核心功能,包括订单管理、商品管理、用户管理、支付管理和物流管理,并介绍了有效的测试技巧,如理解API文档、设计测试用例、搭建测试环境、自动化测试、压力测试、安全性测试等。文章还详细阐述了电商API的多样化用途,如商品信息获取、订单管理自动化、用户数据管理、库存同步、物流跟踪、支付处理、促销活动管理、评价管理、数据报告和分析、扩展平台功能及跨境电商等,旨在为开发者和电商平台提供有益的参考。
26 0
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
76 2
|
2天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析

推荐镜像

更多