Python单元测试浅析
测试的意义
人们针对一个具体问题,通过分析和设计,最后用编程语言写出了一个程序,如果它通过了语言解释器(编译器)的检查,可以运行了,那么下一步的工作就是设法确认它确实满足了我们需求。这篇文章就是讨论怎么确认程序是否满足用户提出的需求。
满足需求,换言之就是功能正常,确认功能正常可以从以下几个方面确认:
- 定义的函数对于所有正确的参数都能返回正确的结果
- 写出的程序对所有合适的输入都能产生正确的输出
量化后的做法就是通过一系列的试运行,检查程序的行为、输入和输出,如果检查中发现了问题,就纠正、改进。这个也是功能测试和安全测试的初衷。
测试用例
测试考虑的基本问题就是怎么运行程序,需要提供什么数据,才能最大限度的检查程序的各种行为和情况,最大可能的挖出程序中的错误和缺陷。基于设计什么测试流程、提供什么参数这种检查程序运行的一套数据被称为一个测试用例。一个测试用例就是可量化的测试流程。
确认测试用例又区分两类方式:
黑盒测试
就是不看代码,直接上手程序的使用测试。这里不讨论黑盒测试。白盒测试
白盒测试的基础是看程序的内部结构(代码)和可能产生的执行路径,根据内部结构来选择测试的用例,使程序在试验性运行中就能表示出尽可能多的不同行为。这个做法的基本理念就是:如果所有可能执行的路径(顺序、条件、while、for、嵌套...执行结构)都能给出正确的结果,那么程序的正确性就能得到保证。
测试函数功能案例
各类的语言都会提供单元测试的库,Python也不例外,python一般使用PyUnit(unittest)库,unittest是Python自带的单元测试框架,用于编写和运行可重复的测试,下面介绍怎么用unittest来测试函数的用法,我这里只是简单用了几个测试方法,更多测试方法请查阅官网(https://docs.python.org/3/library/unittest.html)。
3个需要测试的函数:
def mysum(a, b):
return a + b
def mysubtraction(a, b):
return a - b
def is_evenNumbers(x):
if (x % 2) == 0:
return True
else:
return False
测试函数的方法:
import unittest
import testbox.mymath as mymath
class Test(unittest.TestCase):
def setUp(self):
print("The unit test function start.")
def test_mysum(self):
self.assertEqual(mymath.mysum(1, 2), 3, "mysum function have error!")
def test_mysubtraction(self):
self.assertEqual(mymath.mysubtraction(2, 1), 1, "mysubtraction function have error!")
def test_is_evenNumbers(self):
self.assertTrue(mymath.is_evenNumbers(2), "error")
def test_is_evenNumbers2(self):
self.assertFalse(mymath.is_evenNumbers(3), "error")
def tearDown(self):
print("The unit test end.")
if __name__ == '__main__':
unittest.main()
输出:
Testing started at 12:26 PM ...
The unit test function start.
The unit test end.
The unit test function start.
The unit test end.
The unit test function start.
The unit test end.
The unit test function start.
The unit test end.
assert关键字的用法
功能其实和上面测试函数用法是一样的,只不过assert可以直接使用在代码里。这个关键字也比较生僻,也没见什么场景需要用它,也就这里为了做个案例,我才用它写了个demo。
def testasserts(a):
assert a == 2, Exception("parameter a not is 2, so have a error.")
if a == 2:
print("function run.")
print("OK. function end.")
if __name__ == '__main__':
testasserts(1)
print("Program is end.")
输出:
Traceback (most recent call last):
File "/Users/Mysticbinary/Document/code/personage/python/TestPython1/testbox/testadd.py", line 9, in <module>
testasserts(1)
File "/Users/Mysticbinary/Document/code/personage/python/TestPython1/testbox/testadd.py", line 2, in testasserts
assert a == 2, Exception("parameter a not is 2, so have a error.")
AssertionError: parameter a not is 2, so have a error.
测试类功能案例
类功能的测试和函数测试一样,只不过有一个窍门就是,测试、使用类的时候都需要先实例化类,而实例化类的操作,都可以放在setUp()里面操作。
需要测试的类:
class Library:
allBook = ["php", "java"]
def __init__(self):
print("Library class create completion.")
def savebook(self, bookname):
self.allBook.append(bookname);
return self.allBook
def showbook(self):
print(self.allBook)
return self.allBook
测试类的方法:
import unittest
import testbox.myclass as myc
class TestClass(unittest.TestCase):
def setUp(self):
print("The unit test class start.")
self.library = myc.Library()
self.newbook = "python"
def test_savebook(self):
self.assertIn(self.newbook, self.library.savebook(self.newbook), "errow 1")
def test_showbook(self):
self.assertIn(self.newbook, self.library.showbook(), "errow 2")
def tearDown(self):
print("The unit test end.")
if __name__ == '__main__':
unittest.main()
输出:
Testing started at 12:31 PM ...
The unit test class start.
Library class create completion.
The unit test end.
The unit test class start.
Library class create completion.
['php', 'java', 'python']
The unit test end.
安全测试案例-短信轰炸
我前面说过,功能测试和安全测试都有同样的初衷,但是具体的测试手法两者不太一样,但是一些特定的场景下,使用单元测试的方法,也是能测试一些安全问题的,比如说测接口越权、短信接口重复导致的短信轰炸问题等。我这里只是抛砖引玉一下通过单元测试的手法来做安全测试的例子,但为做深入研究。
def send_message(phone):
keys = phones_dict.keys()
if phone not in keys:
phones_dict[phone] = 0
else:
if phones_dict[phone] < 10:
# 执行发短信的流程
phones_dict[phone] = (phones_dict[phone] + 1)
print("已经发送了{}次短信".format(phones_dict[phone]))
return "success"
else:
print("抱歉,该{}手机号 已经达到今天发短信的上限,请明天再来。".format(phone))
return "error"
测试发短信函数安全的测试用例:
def test_send_message(self):
result = list()
for i in range(0, 11):
result.append(sms.send_message("13193388105"))
print(result)
self.assertNotIn("error", result, "send_message have error.")
输出:
Testing started at 9:48 PM ...
The unit test function start.
已经发送了1次短信
已经发送了2次短信
已经发送了3次短信
已经发送了4次短信
已经发送了5次短信
已经发送了6次短信
已经发送了7次短信
已经发送了8次短信
已经发送了9次短信
已经发送了10次短信
[None, 'success', 'success', 'success', 'success', 'success', 'success', 'success', 'success', 'success', 'success']
The unit test end.
__main__全局变量解释
除了单元测试,设置模块的运行入口(main)也是一种测试方式,就是针对每个模块单独的调用里面的函数。__main__其实是一个全局变量,解释器发现如果该模块是被导入的,那么__main__就会被赋值为这个模块的名字,如果这个模块是作为主模块启动时,那么解释器就会给__main__赋值为“main”字符串。
总结
- 建议不要在程序上线的时候还带着assert、print之类的调试语句、避免信息泄露。
- 单元测试不单只用于功能测试,也可以用在一些特定的安全测试里(具体范围有那些,我没有研究,如果有需求的话,我可能继续深入研究)。
- unittest的断言非常简单易用,基本看一眼就能懂,但是懂断言的用法,不代表你就会写测试用例,能看到程序代码的执行结构才是写出测试的关键所在。一句话就是:写断言易,看代码不易。
- 目前还有一种流行的开发方式叫作测试驱动开发,这种方式强调先编写测试用例,然后再编写函数和方法。也就是在开发某个功能之前,先定义好该功能的最终结果(测试用例关注函数的执行结果),然后再去开发该功能。就像建筑工人在砌墙之前,要先拉好一根笔直的绳子(作用相当于测试用例),然后再开始砌墙,这样砌出来的墙就会符合标准。所以说测试驱动开发也是一种先定义接口,后开发的模式,这样做比较规范,但是对于开发人员来说成本可能有点高,因为有些接口需要在开发的时候才知道返回什么,或者开发的时候也需要经常修改。这种预先定义开发方式,只能说优缺点各半吧。
Python单元测试浅析的更多相关文章
- The Hacker's Guide To Python 单元测试
The Hacker's Guide To Python 单元测试 基本方式 python中提供了非常简单的单元测试方式,利用nose包中的nosetests命令可以实现简单的批量测试. 安装nose ...
- [译]PyUnit—Python单元测试框架(1)
1. 原文及参考资料 原文链接:http://docs.python.org/2/library/unittest.html# 参考文档: http://pyunit.sourceforge.net/ ...
- Python单元测试PyUnit框架轻度整改
原理 参考:单元测试原理 背景 年后有段时间没写代码了,所以趁着周末找了个python单元测试玩下,测试自己的Android应用.发现PyUnit虽然在单个脚本文件中添加多个测试用例,比如官网提供的方 ...
- Python单元测试框架
目录 概况 系统要求 使用PyUnit构建自己的测试 安装 测试用例介绍 创建一个简单测试用例 复用设置代码:创建固件 包含多个测试方法的测试用例类 将测试用例聚合成测试套件 嵌套测试用例 测试代码的 ...
- 一种数据与逻辑分离的Python单元测试工具
一种数据与逻辑分离的Python单元测试工具 几个概念 TestCase TestCase是一个完整的测试单元,最小的测试执行实体,就是我们常说的测试用例. TestSuite 以某种特性将测试用例组 ...
- Python单元测试框架之pytest 4 -- 断言
From: https://www.cnblogs.com/fnng/p/4774676.html Python单元测试框架之pytest -- 断言 2015-08-31 23:57 by 虫师, ...
- Python单元测试框架之pytest 3 -- fixtures
From: https://www.cnblogs.com/fnng/p/4769020.html Python单元测试框架之pytest -- fixtures 2015-08-29 13:05 b ...
- Python单元测试框架之pytest 2 -- 生成测试报告
From: https://www.cnblogs.com/fnng/p/4768239.html Python单元测试框架之pytest -- 生成测试报告 2015-08-29 00:40 by ...
- Python单元测试框架unittest使用方法讲解
这篇文章主要介绍了Python单元测试框架unittest使用方法讲解,本文讲解了unittest概述.命令行接口.测试案例自动搜索.创建测试代码.构建测试套件方法等内容,需要的朋友可以参考下 概 ...
随机推荐
- java中 &&与& ||与| 的区别
public class Demo { public static void main(String[] args) { int i = 5; int j = 3; // || 与 | 的区别 boo ...
- VS2005进行WORD文档开发
折腾了将近一个月的WORD文档开发终于告一段落.这件事已经很多大牛已经做过了.并且很多方法都已经非常详细,提供的资料也非常齐全.不过由于时间的久远并且较为散乱.所以我在学习时间过程中还是走了一些些弯路 ...
- Linux-c glib库hash表GHashTable介绍
百度云glib 链接:https://pan.baidu.com/s/1W9qdlMKWRKIFykenTVuWNQ 密码:ol6y hash表是一种提供key-value访问的数据结构,通过指定的 ...
- Leetcode145. Binary Tree Postorder Traversal二叉树的后序遍历
给定一个二叉树,返回它的 后序 遍历. 进阶: 递归算法很简单,你可以通过迭代算法完成吗? 递归: class Solution { public: vector<int> res; ve ...
- linux系统下重要的分区及其作用
下面列出来的是linux系统下重要的分区及其作用/bin :bin是binary的缩写;/boot :存放启动Linux时使用的一些核心文件;/root :root(超级管理员)的用户主目录;/sbi ...
- 后缀数组(SA)及height数组
最近感觉自己越来越蒟蒻了--后缀数组不会,费用流不会-- 看着别人切一道又一道的题,我真是很无奈啊-- 然后,我花了好长时间,终于弄懂了后缀数组. 后缀数组是什么? 后缀SASASA数组 给你一个字符 ...
- 阿里云 Aliplayer高级功能介绍(六):进度条标记
基本介绍 Aliplayer在进度条上提示时间和缩略图功能外,还可以进行视频内容的提示打点,当然不止是进度条上显示打点的内容,还提供一组接口,方便用户进行打点时间和内容的获取, 基本UI如下图所示: ...
- C语言中结构体的深拷贝和浅拷贝
C++ 的浅拷贝和深拷贝(结构体) 拷贝有两种:深拷贝,浅拷贝 浅拷贝:拷贝过程中是按字节复制的,对于指针型成员变量只复制指针本身,而不复制指针所指向的目标 (1)结构体中不存在指针成员变量时 typ ...
- 释放内存触发断点及数组、指针的NULL初始化
Visual Studio调试时,出现“触发一个断点”内存释放出现异常 数组和对应指针的NULL初始化 数组使用之前要先对其初始化 char Outi[4] = { NULL }; char Outj ...
- SpringData初探
前言 项目中用到这个,没有学过,手动搭建,测试执行流程, 理论的东西有时间再补充 Maven依赖 <?xml version="1.0" encoding="UTF ...