让我们用官网上的一个简单的例子来先看看Unittest的使用方式:
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
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
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
一个测试用例是由unittest.Testcase来创建的,上面的代码里面三个测试用例分别对应的三种方式都是以'test'来开头,这种命名方式可以明确的告诉test runner需要运行的测试用例是哪些。
每一个测试用例里面用来做断言的函数就是assert类的函数,包括assertEqual(判断相等),assertTrue(判断为真),assertFalse(判断为假)等等,关于assert的所有用法可以参见:https://docs.python.org/3.5/library/unittest.html#assert-methods
如果要想抛出异常(RuntimeError, TypeError, NameError),则会使用到函数assertRaise的方式。
接下来我们再看一个例子,现在有一个测试的类calculator.py:
class Count:
def __init__(self,a,b):
self.a = int(a)
self.b = int(b)
# 加法
def add(self):
return self.a + self.b
# 减法
def sub(self):
return self.a - self.b
# 乘法
def mul(self):
return self.a * self.b
# 加法
def div(self):
return self.a / self.b
如果我们想对里面的4个函数进行测试,下面是用unittest框架写出来的代码:
from Unittest.calculator import Count
import unittest
class TestCount(unittest.TestCase):
#测试的初始化
def setUp(self):
print("test start")
#测试用例add的编写
def test_add(self):
self.Count = Count(2, 3)
self.assertEqual(self.Count.add(),5)
# 测试用例sub的编写
def test_sub(self):
self.Count = Count(6, 3)
self.assertEqual(self.Count.sub(), 3)
# 测试用例mul的编写
def test_mul(self):
self.Count = Count(6, 3)
self.assertEqual(self.Count.mul(), 18)
# 测试用例div的编写
def test_div(self):
self.Count = Count(6, 3)
self.assertEqual(self.Count.div(), 2)
#测试的回收-测试的环境还原
def tearDown(self):
print("test end")
if __name__ == "__main__":
# 构造测试集
suite = unittest.TestSuite()
suite.addTest(TestCount("test_add"))
suite.addTest(TestCount("test_sub"))
suite.addTest(TestCount("test_mul"))
suite.addTest(TestCount("test_div"))
# 测试
runner =unittest.TextTestRunner()
runner.run(suite)
- setup函数和tearDown函数分别对应的是单元测试用例之前的初始化和之后的回收。
- 在Unittest中通过addTest这个函数来构造测试集,在这里可以将需要测试的测试用例一一加入
- 最后通过TextTestRunner运行应该执行的测试用例
我们再来看一下Unitttest的整个静态类图:
从上图可以看出整个书写Unittest的流程为:首先是要写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,整个过程集成在unittest.main模块中。
在上面的例子中,我们已经将相似的功能放到了同一个类中,如果我们将相似的功能放到同一个文件中时,可能就会有以下的结构方式:
testcount/
|-count.py
|-testadd.py
|-testsub.py
|-testmul.py
|-testdiv.py
|-runtest.py
当有多个测试用例需要运行,需要添加新的用例时就可以到相应的文件中去添加,但是此时的runtest.py文件中通过addTest()来添加/删除测试用例还是会很麻烦,Unittest中有个功能可以很好的解决这个问题,这个方式就是discover(),此方法是来自于TestLoader.discover()
discover(start_dir, pattern='test*.py', top_level_dir=None)
- start_dir:要测试的模块名或测试用例目录。
- pattern=‘test*.py’:表示用例文件名的匹配原件
- top_level_dir=None:测试模块的顶层目录,如果没有顶层目录,默认为None
现在通过discover()方法重新实现runtest.py文件的功能。
import unittest
#定义测试用例的目录为当前目录
test_dir ='./'
discover= unittest.defaultTestLoader.discover(test_dir,pattern='test*.py')
编写Web测试用例
以一个查询的具体的单元测试用例为实例,目录如下:
baidu.py 实现的是百度搜索和更改百度设置的功能
youdao.py实现的是有道词典中查询的功能
runtest.py实现将日志输出到report目录下的log.txt文件中
.C:\Program Files\Python35-32\lib\site-packages\selenium\webdriver\remote\webdriver.py:585: DeprecationWarning: use driver.switch_to.alert instead
warnings.warn("use driver.switch_to.alert instead", DeprecationWarning)
.
----------------------------------------------------------------------
Ran 2 tests in 27.463s
OK
- runtest_html.py 中引入了HTMLTestRunner的第三方包,使日志可以用html的格式进行展示
最终代码可参见:http://git.oschina.net/ccsensei/gittest