Python中的单元测试模块Unittest快速入门

前言html

为何须要单元测试?python

若是没有单元测试,咱们会遇到这种状况:已有的健康运行的代码在通过改动以后,咱们没法得知改动以后是否引入了Bug。若是有单元测试的话,只要单元测试所有经过,咱们就能够保证没有Bug被引入。所以,单元测试是保证软件工程质量的一个很重要的方面。web

Python中的单元测试shell

Python最强大的地方在于,开发效率高,而且有丰富的Package,避免重复造轮子。那么Python中的Unittest模块有很丰富的功能提供给咱们调用:完整的测试框架,丰富的拓展,好比咱们能够设置测试以前的一些初始化工做,好比连接数据库等,规划测试集中有哪些测试用例须要跳过,以及跳过的缘由。数据库

Unittest中几个类(Class)的基本概念框架

TestCase 是咱们要写的具体的测试用例
TestSuite 多个测试用例集合在一块儿,中文翻译过来叫测试套件,其实就是测试集。
TestLoader是用来加载TestCase到TestSuite中的(更通俗一点,就是用来把符合咱们定义的条件的测试用例组合起来,成为一个测试集),通常会以参数的形式传进去一些条件,好比收集某个目录下全部的test case组成新的测试集。
TestRunner是来执行测试用例的,测试的结果会保存到TestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息函数

一个简单的测试例子单元测试

 

>>> class MyTest(unittest.TestCase): #Run before whole testcase set execution, decorator classmethod is essential
 @classmethod def setUpClass(self): print("UnitTest Begin...") #Run after whole testcase set execution, decorator classmethod is essential
 @classmethod def tearDownClass(self): print("UnitTest End...") #Run before each test case execution 
    def setUp(self): print("Begin...") #Run after each test case execution
    def tearDown(self): print("End...") def test_1(self): self.assertEqual(1,1) def test_2(self): self.assertEqual(1,2) >>> if __name__ == '__main__':unittest.main() UnitTest Begin... Begin... End... .Begin... End... FUnitTest End... ====================================================================== FAIL: test_2 (__main__.MyTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "<pyshell#41>", line 15, in test_2 AssertionError: 1 != 2

---------------------------------------------------------------------- Ran 2 tests in 0.097s FAILED (failures=1)

 

在这个例子中,有几个函数要注意:学习

setUp()和tearDown():每一个test case执行以前和执行以后要运行的操做:咱们能够在这里定义测试的准备工做,好比连接数据库,web登陆等等。测试

用装饰器classmethod装饰的setUpClass()和tearDownClass(): 跑类中定义的全部test cases以前和以后,须要执行的操做。

test_1()和test_2(),具体的测试用例,必定要以test为开头,由于unittest框架中,定义为,若是TestCase类中以test为开头的函数,将会做为具体的testcase收录进要执行的测试集里。

self.assertEqual(),是TestCase类中的断言函数,用来作判断的,用以判断该条测试用例是否经过。经过名字咱们能够看出,这个函数的意思是判断两个值是否相等,若是相等,则用例经过,若是不等,则用例不经过。相似的,断言函数还有不少:有一个msg参数,若是指定msg参数的值,则将该信息做为失败的错误信息返回

 

三种常见测试写法

第一种: 搜索该模块下全部以test开头的测试用例方法,并自动执行它们

#执行测试用例方案一以下: #unittest.main()方法会搜索该模块下全部以test开头的测试用例方法,并自动执行它们。

import unittest #定义测试类,父类为unittest.TestCase。 #可继承unittest.TestCase的方法,如setUp和tearDown方法,不过此方法能够在子类重写,覆盖父类方法。 #可继承unittest.TestCase的各类断言方法。
class Test(unittest.TestCase): def setUp(self): self.number=raw_input('Enter a number:') self.number=int(self.number) #定义测试用例,以“test_”开头命名的方法 #可以使用unittest.TestCase类下面的各类断言方法用于对测试结果的判断
    def test_case1(self): print self.number self.assertEqual(self.number,10,msg='Your input is not 10') def test_case2(self): print self.number self.assertEqual(self.number,20,msg='Your input is not 20') @unittest.skip('暂时跳过用例3的测试') def test_case3(self): print self.number self.assertEqual(self.number,30,msg='Your input is not 30') def tearDown(self): print 'Test over'
        
#若是直接运行该文件(__name__值为__main__),则执行如下语句,经常使用于测试脚本是否可以正常运行
if __name__=='__main__': #执行顺序是命名顺序:先执行test_case1,再执行test_case2
    unittest.main()

第二种: 构造测试集,实例化test suite(即TestRunner类), 运行test suite中全部的测试用例。

''' 执行测试用例方案二以下: 先构造测试集 实例化测试套件 ''' suite=unittest.TestSuite() #将测试用例加载到测试套件中。 #执行顺序是安装加载顺序:先执行test_case2,再执行test_case1
    suite.addTest(Test('test_case2')) suite.addTest(Test('test_case1')) #执行测试用例 #实例化TextTestRunner类
    runner=unittest.TextTestRunner() #使用run()方法运行测试套件(即运行测试套件中的全部用例)
 runner.run(suite) 

第三种:经过收集指定目录下的目标测试用例,构造测试集再执行

#构造测试集(简化了方案二中先要建立测试套件而后再依次加载测试用例) #执行顺序同方案一:执行顺序是命名顺序:先执行test_case1,再执行test_case2
    test_dir = './' discover = unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py') #执行测试用例 #实例化TextTestRunner类
    runner=unittest.TextTestRunner() #使用run()方法运行测试套件(即运行测试套件中的全部用例)
    runner.run(discover)

 

如何生成HTML和XML格式的测试报告

上面咱们获得的测试结果是文本格式的,可读性很差,而且也没法直接用来做后续的测试结果数据处理,好比测试结果的分类统计等等。

那么有两种方式可供咱们选择:HTML和XML

HTML格式的报告,就是网页格式,可读性会比较好。XML格式的报告,则比较方便做后续的数据处理。

须要注意的是,咱们须要安装额外的package,即HtmlTestRunner和xmlrunner。

在配置好Pip的前提下,能够经过如下命令安装:

pip install html-testrunner pip instll xmlrunner

若是没有配置好pip或者用pip安装失败,则须要用如下方式安装(xmlrunner同理):

1. 下载HTMLTestRunner.py文件:地址 http://tungwaiyip.info/software/HTMLTestRunner.html
2. 将该文件保存在python安装路径下的lib文件夹中。在文件中能import HTMLTestRunner成功,即配置成功。
 
以生成HTML报告为例:
#!/usr/bin/python3 # -*- coding: utf-8 -*-

import unittest import HtmlTestRunner class TestStringMethods(unittest.TestCase): def test_upper(self): self.assertEqual('foo'.upper(),'FOO') def test_isupper(self): self.assertFalse('Foo'.isupper()) def test_split(self): s = 'hello world' self.assertEqual(s.split(),['hello','world']) with self.assertRaises(TypeError): s.split(2) if __name__ == '__main__': suite = unittest.TestSuite() suite.addTest(TestStringMethods('test_upper')) suite.addTest(TestStringMethods('test_isupper')) suite.addTest(TestStringMethods('test_split')) runner = HtmlTestRunner.HTMLTestRunner(output='MyUnitTest') runner.run(suite)

最终咱们会获得一个可读性比较好的网页报告。

XML报告:

 有时咱们须要获得格式化数据的测试报告,此时XML格式就要比HTML格式好的多。

由于XML格式的test result容易被读取和数据处理。

示例代码以下:

#!/usr/bin/python3 # -*- coding: utf-8 -*-

import unittest import xmlrunner class TestStringMethods(unittest.TestCase): def test_upper(self): self.assertEqual('foo'.upper(),'FOO') def test_isupper(self): self.assertFalse('Foo'.isupper()) def test_split(self): s = 'hello world' self.assertEqual(s.split(),['hello','world']) with self.assertRaises(TypeError): s.split(2) if __name__ == '__main__': suite = unittest.TestSuite() suite.addTest(TestStringMethods('test_upper')) suite.addTest(TestStringMethods('test_isupper')) suite.addTest(TestStringMethods('test_split')) #fp = open('result.html','w')
    runner = xmlrunner.XMLTestRunner(output='MyUnitTest') #runner = HtmlTestRunner.HTMLTestRunner(stream=fp,output='MyUnitTest')
    runner.run(suite)

 

获得的结果是这样的:

<?xml version="1.0"?> -<testsuite time="0.000" tests="3" name="TestStringMethods-20181115000346" failures="0" errors="0">

<testcase time="0.000" name="test_upper" classname="TestStringMethods"/>

<testcase time="0.000" name="test_isupper" classname="TestStringMethods"/>

<testcase time="0.000" name="test_split" classname="TestStringMethods"/> -<system-out>

<![CDATA[]]>

</system-out> -<system-err>

<![CDATA[]]>

</system-err>

</testsuite>

 

 

几个利用unittest作测试的实际例子

百度搜索测试用例

from selenium import webdriver import unittest, time class BaiduTest(unittest.TestCase): def setUp(self): self.driver = webdriver.Firefox() self.driver.implicitly_wait(30) #隐性等待时间为30秒
        self.base_url = "https://www.baidu.com"
    
    def test_baidu(self): driver = self.driver driver.get(self.base_url + "/") driver.find_element_by_id("kw").clear() driver.find_element_by_id("kw").send_keys("unittest") driver.find_element_by_id("su").click() time.sleep(3) title=driver.title self.assertEqual(title, u"unittest_百度搜索") def tearDown(self): self.driver.quit() if __name__ == "__main__": unittest.main()

有道翻译测试用例

from selenium import webdriver import unittest, time class YoudaoTest(unittest.TestCase): def setUp(self): self.driver = webdriver.Firefox() self.driver.implicitly_wait(30) #隐性等待时间为30秒
        self.base_url = "http://www.youdao.com"
    
    def test_youdao(self): driver = self.driver driver.get(self.base_url + "/") driver.find_element_by_id("translateContent").clear() driver.find_element_by_id("translateContent").send_keys(u"你好") driver.find_element_by_id("translateContent").submit() time.sleep(3) page_source=driver.page_source self.assertIn( "hello",page_source) def tearDown(self): self.driver.quit() if __name__ == "__main__": unittest.main()

web测试用例:经过测试套件TestSuite来组装多个测试用例。

import unittest from test_case import test_baidu from test_case import test_youdao #构造测试集
suite = unittest.TestSuite() suite.addTest(test_baidu.BaiduTest('test_baidu')) suite.addTest(test_youdao.YoudaoTest('test_youdao')) if __name__=='__main__': #执行测试
    runner = unittest.TextTestRunner() runner.run(suite)

 

参考连接:

1. unittest单元测试框架总结

2. unittest — Unit testing framework https://docs.python.org/3/library/unittest.html

3. Python单元测试unittest

4. Python3 unittest断言详解

5. Python3 unittest单元测试

6. Python HTMLTestRunner 学习

相关文章
相关标签/搜索