【软件测试】自动化测试之unittest框架

1.什么是unittest框架

unittest 是python 的单元测试框架,它主要有以下作用:

  • 提供用例组织与执行
    当你的测试用例只有几条时,可以不必考虑用例的组织,但是,当测试用例达到成百上千条时,大量的测试用例堆砌在一起,就产生了扩展性与维护性等问题,此时需要考虑用例的规范与组织问题了。单元测试框架就是来解决这个问题的。
  • 提供丰富的比较方法
    在用例执行完之后都需要将实际结果与预期结果进行比较(断言),从而断定用例是否可以顺利通过。单元测试一般会提供丰富的断言方法。例如,判断相等/不相等、包含/不包含、True/False等断言方法。
  • 提供丰富的日志
    当测试用例执行失败时能抛出清晰的失败原因,当所有用例执行完成后能提供丰富的执行结果。例如,总的执行时间,失败用例数,成功用例数等

2.unittest的简单使用

下面为unittest框架的脚本:

import unittest

from selenium import webdriver
import time

# 定义一个类继承unittest.TestCase
class Baidu1(unittest.TestCase):
    # 测试固件
    # 环境的初始化
    def setUp(self):
        print("--setUp--")
        # self 定义的是全局变量,否则只能在本方法内部使用
        self.driver = webdriver.Chrome()
        # 访问的URL
        self.url = "https://www.baidu.com"
        self.driver.maximize_window()
        time.sleep(3)
    # 测试环境的还原
    def tearDown(self):
        print("--tearDown--")
        self.driver.quit()

    # 测试用例 必须以test_开头 否则不识别,测试用例的执行顺序按照测试方法的字典序升序执行
    def test_t1(self):
        driver = self.driver
        url = self.url
        driver.get(url)
        driver.find_element_by_link_text("hao123").click()
        driver.implicitly_wait(3)
        print(driver.title)
        time.sleep(3)

    # 注解:忽略测试用例的执行
    @unittest.skip("skipping")
    def test_t2(self):
        driver = self.driver
        url = self.url
        driver.get(url)
        driver.find_element_by_id("kw").send_keys("胡歌")
        driver.find_element_by_id("su").submit()
        time.sleep(3)
        print(driver.title)
        time.sleep(3)

    def test_t3(self):
        driver = self.driver
        url = self.url
        driver.get(url)
        driver.find_element_by_id("kw").send_keys("刘浩存")
        driver.find_element_by_id("su").submit()
        print(driver.title)
        time.sleep(3)
# 主方法 测试方法执行入口
if __name__ == "__main__":
    unittest.main()
  • 创建步骤

  • 1.定义一个类继承unittest.TestCase;

  • 2.初始化测试固件;

    setUp() 和 setDown() 是unittest框架中的测试固件

  • 3.编写测试用例

    测试用例的方法均以 test_ 开头,以test_开头命名的方法,是测试方法,在运行整个类的时候会默认执行;

  • 4.编写主方法

    unittest提供了全局的main()方法,使用它可以方便地将一个单元测试模块变成可以直接运行的测试脚本。main()方法搜索所有包含在该模块中以”test"命名的测试方法,并自动执行他们。

3.批量执行测试脚本

在上述测试测试脚本中,我们定义了三个测试用例,我们可以依次执行多个测试用例,当我们实际开发环境中针对不同功能在多个类中写了多个测试我们又该怎么一次执行所有测试脚本呢,测试就需要用到测试套件,测试套件可以批量执行多个类中的测试用例,下面演示使用:

  • 定义两个测试类
    测试1
import unittest

from selenium import webdriver
import time

# 定义一个类继承unittest.TestCase
class Baidu1(unittest.TestCase):
    # 测试固件
    # 环境的初始化
    def setUp(self):
        print("--setUp--")
        # self 定义的是全局变量,否则只能在本方法内部使用
        self.driver = webdriver.Chrome()
        # 访问的URL
        self.url = "https://www.baidu.com"
        self.driver.maximize_window()
        time.sleep(3)
    # 测试环境的还原
    def tearDown(self):
        print("--tearDown--")
        self.driver.quit()

    # 测试用例 必须以test_开头 否则不识别,测试用例的执行顺序按照测试方法的字典序升序执行
    def test_t1(self):
        driver = self.driver
        url = self.url
        driver.get(url)
        driver.find_element_by_link_text("hao123").click()
        driver.implicitly_wait(3)
        print(driver.title)
        time.sleep(3)

    # 注解:忽略测试用例的执行
    @unittest.skip("skipping")
    def test_t2(self):
        driver = self.driver
        url = self.url
        driver.get(url)
        driver.find_element_by_id("kw").send_keys("胡歌")
        driver.find_element_by_id("su").submit()
        time.sleep(3)
        print(driver.title)
        time.sleep(3)

    def test_t3(self):
        driver = self.driver
        url = self.url
        driver.get(url)
        driver.find_element_by_id("kw").send_keys("刘浩存")
        driver.find_element_by_id("su").submit()
        print(driver.title)
        time.sleep(3)
# 主方法 测试方法执行入口
if __name__ == "__main__":
    unittest.main()

测试2

import unittest

from selenium import webdriver
import time

# 博客浏览的自动化测试
class Baidu2(unittest.TestCase):
    # 测试固件
    def setUp(self):
        print("--setUp--")
        self.driver = webdriver.Chrome()
        self.url = "https://blog.csdn.net/qq_57549633"
        self.driver.maximize_window()
        time.sleep(3)
    # 测试环境的还原
    def tearDown(self):
        print("--tearDown--")
        self.driver.quit()

    # 测试用例 必须以test_开头 否则不识别
    def test_t1(self):
        driver = self.driver
        url = self.url
        driver.get(url)
        driver.find_element_by_xpath("//*[@id='userSkin']/div[2]/div/div[2]/div[1]/div[2]/div/div/div[1]/article/a/div[1]/h4").click()
        driver.back()
        time.sleep(3)

    def test_t2(self):
        driver = self.driver
        url = self.url
        driver.get(url)
        driver.find_element_by_xpath("//*[@id='userSkin']/div[2]/div/div[2]/div[1]/div[2]/div/div/div[7]/article/a/div[1]").click()
        driver.back()
        time.sleep(3)
        print(driver.title)
        time.sleep(3)

    def test_t3(self):
        driver = self.driver
        url = self.url
        driver.get(url)
        driver.find_element_by_xpath("//*[@id='userSkin']/div[2]/div/div[2]/div[1]/div[2]/div/div/div[13]/article/a/div[1]/h4").click()
        driver.back()
        print(driver.title)
        time.sleep(3)
        
# 主方法
if __name__ == "__main__":
    unittest.main()
  • addTest()方法
    TestSuite类的addTest()方法可以把不同的测试类中的测试方法组装到测试套件中,但是addTest()一次只能把一个类里面的一个测试方法组装到测试套件中。方式如下:
    将testbaidu1.py、testbaidu2.py中的测试方法放到一个测试套件中,在testsuite.py中实现。
import unittest
import TestBaidu1
import TestBaidu2
from selenium import webdriver

driver=webdriver.Chrome()

driver.get("https://www.baidu.com")

# 组织测试套件方法
def creatSuit():
    # 1.把不同的测试脚本的类中的需要执行的测试方法放在一个测试套件中
    suit=unittest.TestSuite()
    suit.addTest(TestBaidu1.Baidu1("test_t1"))
    suit.addTest(TestBaidu1.Baidu1("test_t2"))
    suit.addTest(TestBaidu2.Baidu2("test_t3"))
    return suit
# 主方法加载套件
if __name__=="__main__":
  suite = creatSuit()
  # verbosity 日志显示级别,分为 0 1 2
  runner = unittest.TextTestRunner(verbosity=2)
  runner.run(suite)
  • makeSuite()和TestLoader()的应用
    在unittest 框架中提供了makeSuite() 的方法,makeSuite可以实现把测试用例类内所有的测试case组成的测试套件TestSuite ,unittest 调用makeSuite的时候,只需要把测试类名称传入即可。
    TestLoader 用于创建类和模块的测试套件,一般的情况下,使TestLoader().loadTestsFromTestCase(TestClass) 来加载测试类。
import unittest
import TestBaidu1
import TestBaidu2
from selenium import webdriver


driver=webdriver.Chrome()

driver.get("https://www.baidu.com")

# 组织测试套件方法
def creatSuit():
    # 2.将一个测试脚本中的类中的所有方法都添加到套件中
    suit=unittest.TestSuite()
    suit.addTest(unittest.makeSuite(TestBaidu1.Baidu1))
    suit.addTest(unittest.makeSuite(TestBaidu2.Baidu2))
  
    # suite1 = unittest.TestLoader().loadTestsFromTestCase(testbaidu1.Baidu1)
    # suite2 = unittest.TestLoader().loadTestsFromTestCase(testbaidu2.Baidu2)
    # suite = unittest.TestSuite([suite1, suite2])
     return suite
# 主方法加载套件
if __name__=="__main__":
  suite = creatSuit()
  # verbosity 日志显示级别,分为 0 1 2
  runner = unittest.TextTestRunner(verbosity=2)
  runner.run(suite)
  • discover()的应用
    discover 是通过递归的方式到其子目录中从指定的目录开始, 找到所有测试模块并返回一个包含它们对象的TestSuite ,然后进行加载与模式匹配唯一的测试文件,discover 参数分别discover(dir,pattern,top_level_dir=None)
import unittest
import TestBaidu1
import TestBaidu2
from selenium import webdriver

driver=webdriver.Chrome()

driver.get("https://www.baidu.com")

# 组织测试套件方法
def creatSuit():
    # 3.将整个文件夹下所有的测试脚本的测试用例都添加到套件中
    discover=unittest.defaultTestLoader.discover("../Test", pattern="TestBaidu*.py", top_level_dir=None)
    return discover
# 主方法加载套件
if __name__=="__main__":
  suite = creatSuit()
  # verbosity 日志显示级别,分为 0 1 2
  runner = unittest.TextTestRunner(verbosity=2)
  runner.run(suite)

用例的执行顺序:unittest 框架默认加载测试用例的顺序是根据ASCII 码的顺序,数字与字母的顺序为: 09,AZ,a~z 。
所以, TestAdd 类会优先于TestBdd 类被发现, test_aaa() 方法会优先于test_ccc() 被执行。对于测试
目录与测试文件来说, unittest 框架同样是按照这个规则来加载测试用例。

4.unittest断言

自动化的测试中, 对于每个单独的case来说,一个case的执行结果中, 必然会有期望结果与实际结果, 来判断该case是通过还是失败, 在unittest 的库中提供了大量的实用方法来检查预期值与实际
值, 来验证case的结果。
下面是一些常用的断言:
在这里插入图片描述
代码演示:

import time

from selenium import webdriver
import unittest

# 定义一个类继承unittest.TestCase
class Test(unittest.TestCase):
    # 测试固件
    # 环境的初始化
    def setUp(self):
        print("--setUp--")
        # self 定义的是全局变量,否则只能在本方法内部使用
        self.driver = webdriver.Chrome()
        self.url = "https://www.baidu.com"
        self.driver.maximize_window()
        time.sleep(3)
    # 测试环境的还原
    def tearDown(self):
        print("--tearDown--")
        self.driver.quit()

    # 测试用例
    def test_t1(self):
        driver=self.driver
        url=self.url
        driver.get(url)
        time.sleep(3)
        driver.find_element_by_id("kw").send_keys("胡歌")
        driver.find_element_by_id("su").click()
        driver.implicitly_wait(5)
        print(driver.title)
        # self.assertEqual("胡歌_百度搜索", driver.title, msg="未打开网页")
        self.assertTrue("百度一下,你就知道" == driver.title, msg="内容不相等")
        time.sleep(5)
        driver.quit()

5.HTML报告生成

脚本执行完毕之后,还需要看到HTML报告,下面我们就通过HTMLTestRunner.py 来生成测试报告。
HTMLTestRunner支持python2.7。python3可以参见http://blog.51cto.com/hzqldjb/1590802来进行修改。
HTMLTestRunner.py 文件,下载地址: http://tungwaiyip.info/software/HTMLTestRunner.html
下载后将其放在testcase目录中去或者放入…\Python27\Lib 目录下(windows)。

import HTMLTestRunner
import sys
import unittest
from selenium import webdriver
import os
import time

driver = webdriver.Chrome()

driver.get("https://www.baidu.com")

# 组织测试套件的方法
def creatSuit():
    # Test目录下所有的测试用例
    discover=unittest.defaultTestLoader.discover("../Test", pattern="Test*.py", top_level_dir=None)
    return discover

if __name__ == "__main__":
    # 当前路径、 等同于./
    curpath = sys.path[0]
     # 取当前时间
    now = time.strftime("%Y-%m-%d-%H %M %S", time.localtime(time.time()))
    if not os.path.exists(curpath + '/resultreport'):
           os.makedirs(curpath + '/resultreport')
    # 文件名
    filename = curpath + '/resultreport/' + now + 'resultreport.html'
    with open(filename, 'wb') as fp:
         # 出html报告
         runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title=u'测试报告',description=u'用例执行情况',verbosity=2)
         suite = creatSuit()
         runner.run(suite)

在resultreport目录下生成的测试报告:
在这里插入图片描述
测试报告中会详细展示用例的执行情况(我这里测试用例全部通过):

5.异常捕捉与错误截图

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

 # -*- coding: utf-8 -*-
from selenium import webdriver
import unittest
import time
import os


class Baidu1(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(30)
        self.base_url = "http://www.baidu.com/"
        self.verificationErrors=[]
        self.accept_next_alert = True

    def tearDown(self):
        self.driver.quit()
        self.assertEqual([],self.verificationErrors)

      # 忽略此测试用例
    @unittest.skip("skipping")
    def test_baidusearch(self):
        driver = self.driver
        driver.get(self.base_url)
        driver.find_element_by_id("kw").clear()
        driver.find_element_by_id("kw").send_keys(u"大虞海棠")
        driver.find_element_by_id("su").click()
        time.sleep(6)


    def test_baidu(self):
        driver = self.driver
        driver.get(self.base_url)
        driver.maximize_window()
        driver.find_element_by_id("kw").send_keys("向往的生活")
        driver.find_element_by_id("su").click()
        time.sleep(6)
        print(driver.title)
        try:
            self.assertEqual(driver.title, u"百度一下,你就知道", msg="不相等")
        except:
            self.saveScreenShot(driver, "hao.png")   # 出现异常就调用截图函数进行截图
        time.sleep(3)

    # 截图函数
    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(3)

    if __name__ == "__main__":
        unittest.main()

上述代码中,异常信息被捕获,在image目录下生成错误截图:
在这里插入图片描述

6.数据驱动

当需要测试不同条件下的测试用例时,为提升测试效率就需要使用数据驱动DDT。python 的unittest 没有自带数据驱动功能。所以如果使用unittest,同时又想使用数据驱动,那么就可以使用DDT来完成。

# -*- coding: utf-8 -*-
from selenium import webdriver
import unittest
import time
from ddt import ddt, unpack, data, file_data
import sys, csv

# 获取文本文件方法
def getTxt(file_name):
    # ([周迅,周迅_百度搜索],[张国荣,张国荣_百度搜索],[张一山,张一山_百度搜索])
    rows = []
    path = sys.path[0]
    with open(path+'/data/'+file_name, 'rt') as f:
        readers = csv.reader(f, delimiter=',', quotechar='|')
        next(readers, None)
        for row in readers:
            temprows=[]
            for i in row:
                # 周迅,周迅_百度搜索
                temprows.append(i)
            rows.append(temprows)
        return rows

@ddt
class Baidu1(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(30)
        self.base_url = "http://www.baidu.com/"
        self.driver.maximize_window()
        self.verificationErrors=[]
        self.accept_next_alert = True
    def tearDown(self):
        self.driver.quit()
        self.assertEqual([],self.verificationErrors)

    # 获取json数据
    # @file_data('test_baidu_data.json') ([周迅,周迅_百度搜索],[张国荣,张国荣_百度搜索],[张一山,张一三_百度搜索])
    # 获取多个变量时需要使用 @unpack
    # @data(['Lisa', u"Lisa_百度搜索"], [u"双笙", u"7887双笙_百度搜索"], [u"张一山",u"张一三_百度搜索"])
    # @unpack
    @unittest.skip("skipping")
    @data("王凯", "Lisa", "特朗普", "蒋欣")
    def test_baidu1(self, value):
        driver = self.driver
        driver.get(self.base_url + "/")
        driver.maximize_window()
        driver.find_element_by_id("kw").clear()
        driver.find_element_by_id("kw").send_keys(value)
        driver.find_element_by_id("su").click()
        # time.sleep(6)
        # self.assertEqual(driver.title, expected_value, msg="搜索结果和期望不一致!")
        time.sleep(6)


    # @unittest.skip("skipping")
    # 获取文本数据 [周迅, 周迅_百度搜索], [张国荣, 张国荣111_百度搜索], [张一山,张一山_百度搜索]
    # @data(['Lisa', u"Lisa_百度搜索"], [u"双笙", u"7887双笙_百度搜索"])
    # @unpack
    @data(*getTxt('test_baidu_data.txt'))
    def test_baidu2(self, value, expected_value):
        driver = self.driver
        driver.get(self.base_url + "/")
        driver.find_element_by_id("kw").clear()
        driver.find_element_by_id("kw").send_keys(value)
        driver.find_element_by_id("su").click()
        driver.maximize_window()
        time.sleep(6)
        #判断搜索网页的title和我们期望的是否一致
        self.assertEqual(expected_value, driver.title, msg="和预期搜索结果不一致!")
        print(expected_value)
        print(driver.title)
        time.sleep(6)

if __name__ == '__main__':
    unittest.main()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python是一种高级编程语言,它被广泛应用于各种领域,包括软件开发、数据分析和自动化测试等。在自动化测试领域,Python也有很多成熟的框架可供选择。 其中,Python的接口自动化测试框架有很多,以下是其中几个比较常用的框架: 1. requests:requests是一个简洁而优雅的HTTP库,它可以方便地发送HTTP请求并处理响应。在接口自动化测试中,可以使用requests库发送各种类型的HTTP请求(如GET、POST等),并对响应进行断言和验证。 2. unittestunittest是Python自带的单元测试框架,它提供了一系列的断言方法和测试装置,可以方便地编写和执行接口自动化测试用例。unittest框架支持测试套件的组织和执行,可以进行测试用例的批量执行和结果的统计。 3. pytest:pytest是一个功能强大的Python测试框架,它支持自动发现测试用例、参数化测试测试夹具等高级特性。pytest框架可以与其他库和工具(如requests、mock等)无缝集成,提供了更加灵活和可扩展的接口自动化测试解决方案。 4. Robot Framework:Robot Framework是一个通用的自动化测试框架,它支持关键字驱动的测试方法,并提供了丰富的库和插件,用于编写和执行接口自动化测试用例。Robot Framework可以与Python无缝集成,通过编写自定义关键字和库,实现更加灵活和定制化的接口自动化测试。 以上是几个常用的Python接口自动化测试框架,每个框架都有其特点和适用场景。你可以根据项目需求和个人喜好选择合适的框架进行接口自动化测试

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值