unittest 这个库是python 标准库之一,它属于xUnit 系列,unittest中借鉴了很多Xunit(主要是Junit)的概念,这些概念在主流的测试执行其中大多通用。
任务1.搜索unittest的文档,以便在需要时可以查阅
首先,我们打开浏览器,使用百度等搜索引擎,搜索关键字:
python unittest 文档
这样我们可以直接找到其英文文档:docs.python.org/3/library/u…
但是,我建议阅读英文文档,一般文档上的英文难度并不高。
例1.一个最基础的 unittest例子
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual("foo'.upper0,FOO)
def test isupper(self):
self.assertTrue(FOO'.isupper0)
self.assertFalse"Foo'.isupper0)
def test split(self):
s=‘hello world'
self.assertEqual(s.split),'hello','world])
#check that s.split fails when the separator is not a string
string with self.assertRaises(TypeError):s.split(2)
if_name_=='_main_:
unittest.main0
复制代码
我们一起来看一下例1的意思:
第1行import 了unittest 这个库
第2行定义了一个测试用例的类,注意他继承了unittest的TestCase类。这是因为unittest 只会在Test Case类的子类里寻找要执行的测试方法。
第3-4行定义了第一个测试方法,test_upper 这个命名以test 开头,也是因为unittest规定了只会执行以test开头的方法,这些也就是他要执行的测试方法。
后面几行分别定义了test_isupper 和test_split 两个测试方法。
最后两行if开头的是python 脚本执行入口,通过unittest.main0来调用unittest的测试执行模块开始执行测试。
断言
然后看一下测试方法里的内容:
self.assertEqual(foo’.upper0,’FOO)
这一行的assertEqual 是判断后面的两个对象是否相等,注意前面的self.表示这是当前这个TestCase 类里定义的方法。我们自己写的测试用例里没有包含assertEqual的定义,那么他必然来自父类unittest.TestCase这个类了。
同理,后面的assertTrue,assertFalse 顾名思义就是判断后面的表达式是否为True和为False了。
下面这两行的意思比较难懂
with self.assertRaises(TypeError):
s.split(2)
复制代码
这里用的with 表达式,我们在文件读写那一章里提过。这里也是除了文件读写之外第二个用到with的地方吧。这里的意思是在执行s.split(2)这句话时应该抛出TypeError的异常,然后这句话就在验证这个TypeError有没有被跑出来。
值得一提的是,这么多复杂的断言(还有很多其他的),大多是用来做单元测试的。在单元测试里,我们才会需要去判断一个业务逻辑方法有没有按照预期抛出异常。而当我们用unittest写接口测试、图形界面测试等其他东西时,我们基本用不到这些东西。
更常用更简单的断言
我有一个建议,也是我自己写测试代码的原则:
把代码或脚本的尽量从逻辑上就设计地更简单一些。我们不要十多种断言,只要一种。
像这样:
assert 1+1==3,”1+2 not equal3″
这里assert 不需要带self,因为他不是unittest的TestCase独有的,而是python直接内置的特殊的函数,同时调用assert 也不需要带括号。上面这一行例子用逗号隔开了两个参数,第一个参数是要判断是否为True的表达式,第二个参数是当第一个参数的表达式判断为False时,给用户的错误提示。
比如这一行执行时会报如下错误:
Traceback(most recent call last):
File"15.30.py",line 17,in test_split#这一行会告诉你出错在哪个文件哪个方法第几行
assert1+1==3,"1+2 not equal3#这一行会把出错的那一行打出来
AssertionError:1+2 not equal3#这一行是我们自己写的出错信息
复制代码
这里我们写的“1+2 not equal3″这条出错信息在断言不通过时会完整打印出来,此外,我们还可以加一些变量进这个信息里,比如下面这个例子里,出错提示里带了要判断的变量的值。
a=2
assert a==3,”a should be(but actually(0″.format(”3″,a)
这样一个断言在出错时,会提示:
Traceback(most recent call last):
File"15.30.py",line 19,in test split
assert a==3,"a should be but actually 0".format("3",a)
AssertionError:a should be 3 but actually 2
复制代码
运行unittest
执行这个测试例子有两种方法:
1.命令行形式运行
我把这个例子保存在一个名为15.30.py的文件里后,在命令行这样运行它:python.exe 15.30.py
得到这样的屏幕输出:
Ran 3 tests in 0.001s
ок
以上,3个小圆点表示执行的3个测试的结果都是pass,如果失败了,不会显示小圆点,而会显示表示错误的字母。这种以命令行形式来运行测试的方法,是我们在持续集成系统里使用自动化测试脚本时需要用到的方法,比较常用.
2.在IDE里运行
直接在pycharm里右键,选Run Unittest in xx.py来运行.
这种IDE里运行测试的方法,是平时写测试或调试测试脚本时用的。
任务2.
以IDE和命令行形式分别运行例1,并观察其输出结果。
然后修改例1,使其失败,再次运行,并观察其输出结果的变化。
再次修改例1,使用更常用的assert断言。
在我们看懂了例1之后,后面要怎样写比较大规模的测试呢?
如果是早几年我们学习unittest库,那接下来有很多复杂的东西需要讨论,比如unittest怎样从命令行启动,本章的例子虽然也是从命令行启动,但没有带unittest命令行参数,实际上unittest也是想一个独立的命令行程序一样可以带很多参数的。然后就会讨论一下,unit test怎样发现测试用例,搜索路径,如何把测试用例分组,规定什么情况下跑什么测试用例。感兴趣的同学可以去看unittest文档.
但是现在实际上我们没必要搞这么复杂.
下一节会介绍pytest,这个工具兼容unittest,并且可以很简单地使用。利用pytest,我们可以从逻辑上就把测试执行这件事情变得很简单