Unittest单元测试框架(一)

简介: 单元测试中单元的含义,单元就是人为规定的最小的被测功能模块,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。在实际项目中,单元测试往往由开发人员完成。


一,前言


1,单元测试


软件测试一般按阶段划分为:单元测试,集成测试,系统测试。单元测试(unit testing)是指对软件中的最小可测试单元进行检查和验证。 单元测试中单元的含义,单元就是人为规定的最小的被测功能模块,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。在实际项目中,单元测试往往由开发人员完成。


2,单元测试框架


  • 单元测试其实就是构造数据使用一段代码去测试另一段代码,理论上来说,不使用单元测试框架也能进行单元测试。但如果用于单元测试的代码(即测试用例)增多,在没有测试框架的情况下会变得拥挤、不可管理,这个时候引入测试框架就变得尤为重要。
  • 单元测试框架提供了一种统一的编程模型,可以将测试定义为一些简单的类,这些类中的方法可以调用希望测试的应用程序代码。利用单元测试框架,可以很轻松地插入、设置和分解有关测试的功能,可以直观方便地管理测试用例。
  • 主流的单元测试框架,如Java的Junit、TestNg,python的Unittest、Pyunit、Pytest,通用的自动化测试框架Robot Framework等。


3,单元测试框架作用


  • 提供用例组织与执行
  • 提供丰富的断言方法
  • 提供丰富的日志与测试结果


二,Unittest 测试框架


1,Unittest 简介


Unittest是Python自带的单元测试框架,不仅适用于单元测试,还可用于Web、Appium、接口自动化测试用例的开发与执行。该测试框架可组织执行测试用例,并且提供丰富的断言方法,判断测试用例是否通过,并最终生成测试结果。

Unittest官方文档:https://docs.python.org/3/library/unittest.html


2,Unittest 核心要素


  • TestCase:即测试用例,Unittest提供testCase类来编写测试用例,一个TestCase的实例就是一个测试用例。一条测试用例就是一个完整的测试流程,包括测试前准备环境的搭建(setUp),执行测试代码(run),以及测试后环境的还原(tearDown),通过运行一条测试用例,可以对某一个问题进行验证。
  • Fixture:即测试固件,用于测试用例环境的搭建和销毁。在测试步骤执行前需要为该测试用例准备环境(SetUp),如启动app或打开浏览器,测试步骤执行后需要恢复环境 (TearDown),如关闭app或浏览器,这时候就需要用到Fixture,使代码更简洁。
  • TestSuite:即测试套件,把需要执行的测试用例集合在一起就是TestSuite。使用TestLoader来加载TestCase到TestSuite中。
  • TextTestRunner:即测试执行器,用于执行测试用例。该模块中提供run方法执行TestSuite中的测试用例,并返回测试用例的执行结果,如运行的用例总数、用例通过数、用例失败数。
  • report:即测试报告。unittest框架没有自带的用于生成测试报告的模块或接口,需要使用第三方的扩展模块HTMLTestRunner。


3,Unittest 断言


断言在自动化测试脚本中是很重要的内容,只有设置正确合适的断言才能获取正确的测试结果。Unittest框架提供了自己的断言方法,如下:

断言方法

判断内容

assertEqual(a, b) 判断 a == b
assertNotEqual(a, b) 判断 a != b
assertTrue(x) 判断 bool(x) is True
assertFalse(x) 判断 bool(x) is False
assertIs(a, b) 判断 a is b
assertIsNot(a, b) 判断 a is not b
assertIsNone(x) 判断 x is None
assertIsNotNone(x) 判断 x is not None
assertIn(a, b) 判断 a in b
assertNotIn(a, b) 判断 a not in b
assertIsInstance(a, b) 判断 isinstance(a, b)
assertNotIsInstance(a, b) 判断 not isinstance(a, b)

注意

  • 如果断言成功则该条测试用例通过,断言失败则该条测试用例执行失败,且会抛出AssertionError错误。
  • 以上提供的断言方法中,都有一个msg参数,默认为None。如果msg参数有对应的值,则断言失败后该msg的值会作为失败信息返回,如 assertEqual(a, b, msg="a与b不相等!") 。


三,Unittest 框架使用方法


1,测试需求

测试对象:构造一个类Math,其中包含整数的加、减法运算。

calculator.py

class Math():
    def __init__(self, a, b):
        self.a = int(a)
        self.b = int(b)
    def sum(self):
        '''和'''
        return self.a + self.b
    def sub(self):
        '''差'''
        return self.a - self.b

测试需求:对Math类进行单元测试。接下来针对这个测试需求,使用unittest框架编写测试用例。

项目目录结构:后面的例子中,项目结构如下所示。

微信图片_20220424203359.png

2,编写TestCase(测试用例)


在Unittest框架下创建测试用例,步骤如下:

  • 1),导入unittest模块。
  • 2),创建测试类。测试类的命名不做要求,但需要继承unittest.TestCase类
  • 3),添加setUp()、tearDown()函数,即测试固件。当然还有setUpClass()、tearDownClass() 函数,区别后面会有介绍。
  • 4),定义测试方法,即测试用例。测试方法名称必须以test开头,否则测试时该方法将不会被执行。测试方法里需要添加断言。
  • 5),调试执行测试用例。执行当前模块的测试用例时,调用unittest.main()方法,该方法会搜索该模块下所有以test开头的测试用例方法,并执行。其他方法后面介绍。

针对测试需求,编写测试用例。目录结构如下:

test_sum.py

import unittest
from calculator import Math
class SumTest(unittest.TestCase):
    '''测试Math类中的sum函数'''
    def setUp(self):
        print("开始执行测试用例{}...".format(self))
    def test_sum01(self):
        m = Math(3, 4)
        self.assertEqual(m.sum(), 7)
    def test_sum02(self):
        m = Math(2, 8)
        self.assertEqual(m.sum(), 11)
    def tearDown(self):
        print("测试用例{}执行结束...".format(self))
if __name__ == '__main__':
    unittest.main()

运行结果:

.F
======================================================================
FAIL: test_sum02 (__main__.SumTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:/Users/xiaoqq/Desktop/test_project/demo/testSum.py", line 15, in test_sum02
    self.assertEqual(m.sum(), 11)
AssertionError: 10 != 11
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (failures=1)
开始执行测试用例test_sum01 (__main__.SumTest)...
测试用例test_sum01 (__main__.SumTest)执行结束...
开始执行测试用例test_sum02 (__main__.SumTest)...
测试用例test_sum02 (__main__.SumTest)执行结束...
Process finished with exit code 0

结果显示:

  • test_sum01通过,test_sum02失败。点"."表示通过,"F"表示失败。
  • 测试类中每个测试方法(即测试用例)执行前,都先执行setUp()方法,每个测试方法执行完毕后都要执行tearDown()方法。
  • 断言失败会返回一个AssertionError。


3,在测试用例中添加Fixture(测试夹具)


3.1,测试夹具Fixture的作用对象


在Unittest框架下的测试用例中,使用Fixture有两种方法,作用于两个范围:

  • setUp()、tearDown(),作用于测试方法。即测试类下的每个测试方法执行前先运行setUp(),每个测试方法执行完毕后都要执行tearDown()方法,如testSum.py示例。
  • setUpClass()、tearDownClass(),作用于测试类。即只在整个测试类执行开始时运行setUpClass(),测试类下所有测试方法执行完后运行tearDownClass()。


3.2,setUpClass()、tearDownClass() 举例


test_sum.py修改如下,运行

class SumTest(unittest.TestCase):
    '''测试Math类中的sum函数'''
    @classmethod
    def setUpClass(cls):
        print("开始执行测试用例{}...".format(cls))
    def test_sum01(self):
        m = Math(3, 4)
        self.assertEqual(m.sum(), 7)
    def test_sum02(self):
        m = Math(2, 8)
        self.assertEqual(m.sum(), 11)
    @classmethod
    def tearDownClass(cls):
        print("测试用例{}执行结束...".format(cls))
if __name__ == '__main__':
    unittest.main()

运行结果:

开始执行测试用例<class '__main__.SumTest'>...
测试用例<class '__main__.SumTest'>执行结束...
.F

结果显示,setUpClass()、tearDownClass() 都只运行了一次。注意,这里需要使用装饰器@classmethod


3.3,注意


  • 在测试用例中,setUp() 或 setUpClass() 做初始化的工作,不是必须有这个函数。同样tearDown() 和 tearDownClass() 只做清理的工作,在测试类中不是必须要有。
  • 需要测试的Math类,代码比较简单,没有真正需要用到测试夹具的地方,因此这只是个用法演示。
  • 实际自动化过程中,如Web端UI自动化,一般会将创建浏览器实例放在setUp() ,用例执行完后需要关闭浏览器,将关闭浏览器操作放在tearDown()方法里。示例如下:
import unittest
from selenium import webdriver
class BaiduTest(unittest.TestCase):
    def setUp(self):
        '''打开浏览器,进入百度页面'''
        self.driver = webdriver.Chrome()
        self.driver.maximize_window()
        self.driver.get('https://www.baidu.com')
    def test_01(self):
        print("操作步骤")
    def tearDown(self):
        '''关闭浏览器'''
        self.driver.quit()


4,将测试用例添加至TestSuite(测试套件)


testSum.py模块中,使用了unittest.main()方法执行当前模块里的测试用例。除此之外,Unittest还可以通过测试套件构造测试用例集,再执行测试用例。构造TestSuite常用的方法如下:


4.1,方法一:加载测试用例


  • 1),先通过unittest.TestSuite() 创建测试套件实例对象。
  • 2),再通过addTest() 往测试套件里添加单个测试用例,或通过addTests([...]) 添加多个测试用例(列表中为用例方法名)。
  • 3),执行测试套件里的测试用例

run.py示例:

import unittest
# 导入测试用例模块
from testcase.test_sum import TestDemo
# 第一步:创建TestSuite实例
suite = unittest.TestSuite()
# 第二步:将测试用例添加至TestSuite
# 方式1,添加单条测试用例
suite.addTest(TestDemo('test_sum01'))   # addTest()里参数格式为:测试类('测试方法')
suite.addTest(TestDemo('test_sum02'))
# 方式2,添加多条测试用例
suite.addTests([TestDemo('test_sum01'), TestDemo('test_sum02')])


4.2,方法二:加载测试用例类


  • 1),先通过unittest.TestSuite() 创建测试套件实例对象。
  • 2),再通过unittest.TestLoader()创建加载对象,加载测试用例类

run.py示例:

import unittest
# 导入测试用例模块
from testcase.test_sum import TestDemo
# 创建TestSuite实例
suite = unittest.TestSuite()
# 创建一个加载对象
loader = unittest.TestLoader()
suite.addTest(loader.loadTestsFromTestCase(TestDemo))


4.3,方法三:加载指定路径里的测试用例


  • 1),通过unittest.defaultTestLoader.discover()将指定路径的测试用例加载至测试用例集。注意:这里不需要创建unittest.TestSuite对象
  • 2),如下代码所示,test_dir为指定路径。pattern=test_*.py 表示加载以test_开头的模块中的测试用例,指定运行某模块时pattern参数指定全名即可,如:pattern='test_sum.py'。路径跟pattern参数都可以自定义。

run.py示例

import unittest
test_dir = './testcase'
suite = unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')

编写测试项目时,推荐使用方法三。当然还有其他方法,不多做介绍。


5,使用TextTestRunner执行测试用例


unittest框架执行测试用例之前,需先创建TextTestRunner实例,再调用该实例的run()方法。

# 创建TextTestRunner实例
runner = unittest.TextTestRunner()
# 使用run()方法运行测试套件(即运行测试套件中的所有用例)
runner.run(suite)

run.py修改成如下示例:

import unittest
test_dir = './testcase'
suite = unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')
runner = unittest.TextTestRunner()
runner.run(suite)

运行run.py,结果如下:

.F
======================================================================
FAIL: test_sum02 (test_sum.TestDemo)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Users\xiaoqq\Desktop\test_project\demo\test_sum.py", line 15, in test_sum02
    self.assertEqual(m.sum(), 11)
AssertionError: 10 != 11
----------------------------------------------------------------------
Ran 2 tests in 0.000s
FAILED (failures=1)
开始执行测试用例test_sum01 (test_sum.TestDemo)...
测试用例test_sum01 (test_sum.TestDemo)执行结束...
开始执行测试用例test_sum02 (test_sum.TestDemo)...
测试用例test_sum02 (test_sum.TestDemo)执行结束...
Process finished with exit code 0
相关文章
|
21天前
|
数据可视化 数据管理 测试技术
聊聊自动化测试框架
关于自动化测试框架的一些理解和思考总结,就是上面这些内容,提到的一些框架组件可能存在不合理的地方,仅供参考,如有更好的建议,请指出,不胜感激
25 4
聊聊自动化测试框架
|
1天前
|
Web App开发 敏捷开发 数据管理
自动化测试框架的设计与实现
【9月更文挑战第32天】在软件开发的海洋中,自动化测试如同一艘精确导航的船只,确保我们的应用程序能够在波涛汹涌的技术潮流中稳健航行。本文将带你领略自动化测试框架的设计之美,从搭建基础到功能扩展,再到维护实践,我们将一起探索如何打造一个既高效又灵活的自动化测试体系。
|
17天前
|
敏捷开发 IDE 测试技术
自动化测试框架的选择与应用
【9月更文挑战第16天】在软件开发周期中,测试环节扮演着至关重要的角色。随着敏捷开发和持续集成的流行,自动化测试成为提升软件质量和效率的关键手段。本文将探讨如何根据项目需求选择合适的自动化测试框架,并通过实际案例分析展示其在软件开发过程中的应用。我们将从单元测试、集成测试到端到端测试等多个层面,讨论自动化测试的最佳实践和常见问题解决策略。
|
7天前
|
敏捷开发 Java 测试技术
自动化测试框架的选择与应用
【9月更文挑战第26天】在软件开发的海洋里,自动化测试是那一盏指路明灯。它不仅加快了开发周期,还提升了软件质量。本文将带你探索自动化测试框架的世界,了解它们的核心特性、适用场景及如何根据项目需求做出明智选择。让我们一起启航,找到那把打开高效、稳定软件生产大门的钥匙。
|
7天前
|
敏捷开发 数据管理 测试技术
自动化测试框架的设计与实现
【9月更文挑战第25天】 本文将引导读者深入理解自动化测试框架的核心概念,并展示如何从零开始构建一个简单且有效的自动化测试框架。通过通俗易懂的语言和实际代码示例,我们将探讨测试框架设计的关键步骤、实现方法以及常见问题的解决方案。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的知识和启示。
|
9天前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP的编程实践中,设计模式是解决常见软件设计问题的最佳实践。单例模式作为设计模式中的一种,确保一个类只有一个实例,并提供全局访问点,广泛应用于配置管理、日志记录和测试框架等场景。本文将深入探讨单例模式的原理、实现方式及其在PHP中的应用,帮助开发者更好地理解和运用这一设计模式。
在PHP开发中,单例模式通过确保类仅有一个实例并提供一个全局访问点,有效管理和访问共享资源。本文详细介绍了单例模式的概念、PHP实现方式及应用场景,并通过具体代码示例展示如何在PHP中实现单例模式以及如何在实际项目中正确使用它来优化代码结构和性能。
|
28天前
|
存储 Java 关系型数据库
“代码界的魔法师:揭秘Micronaut框架下如何用测试驱动开发将简单图书管理系统变成性能怪兽!
【9月更文挑战第6天】Micronaut框架凭借其轻量级和高性能特性,在Java应用开发中备受青睐。本文通过一个图书管理系统的案例,介绍了在Micronaut下从单元测试到集成测试的全流程。首先,我们使用`@MicronautTest`注解编写了一个简单的`BookService`单元测试,验证添加图书功能;接着,通过集成测试验证了`BookService`与数据库的交互。整个过程展示了Micronaut强大的依赖注入和测试支持,使测试编写变得更加高效和简单。
50 4
|
1月前
|
IDE 测试技术 持续交付
Python自动化测试与单元测试框架:提升代码质量与效率
【9月更文挑战第3天】随着软件行业的迅速发展,代码质量和开发效率变得至关重要。本文探讨了Python在自动化及单元测试中的应用,介绍了Selenium、Appium、pytest等自动化测试框架,以及Python标准库中的unittest单元测试框架。通过详细阐述各框架的特点与使用方法,本文旨在帮助开发者掌握编写高效测试用例的技巧,提升代码质量与开发效率。同时,文章还提出了制定测试计划、持续集成与测试等实践建议,助力项目成功。
53 5
|
7天前
|
设计模式 测试技术 持续交付
自动化测试框架的设计与实现
【9月更文挑战第25天】本文旨在探讨如何设计并实现一个高效、可扩展的自动化测试框架,以提升软件测试的效率和质量。通过分析当前流行的测试框架特点,结合最佳实践,提出一套完整的解决方案。文章不仅涵盖框架设计的理论依据,还包括具体实现步骤和示例,帮助读者深入理解自动化测试框架的搭建过程。
|
1月前
|
测试技术 C# 图形学
掌握Unity调试与测试的终极指南:从内置调试工具到自动化测试框架,全方位保障游戏品质不踩坑,打造流畅游戏体验的必备技能大揭秘!
【9月更文挑战第1天】在开发游戏时,Unity 引擎让创意变为现实。但软件开发中难免遇到 Bug,若不解决,将严重影响用户体验。调试与测试成为确保游戏质量的最后一道防线。本文介绍如何利用 Unity 的调试工具高效排查问题,并通过 Profiler 分析性能瓶颈。此外,Unity Test Framework 支持自动化测试,提高开发效率。结合单元测试与集成测试,确保游戏逻辑正确无误。对于在线游戏,还需进行压力测试以验证服务器稳定性。总之,调试与测试贯穿游戏开发全流程,确保最终作品既好玩又稳定。
47 4
下一篇
无影云桌面