2018-08-07(16)单元测试(下)

Python基础语法(16)

单元测试

测试用例的核心工作原理 : test case(测试用例); test suite(测试套件), test runner(测试运行器); test fixture(测试装备)

  • TestCase:

    就是一个完整的测试流程,包括测试前准备环境的搭建(setUp),执行测试代码(run),以及测试后环境的还原(tearDown)。单元测试的本质就在这里:一个测试用例是一个完整的测试单元,通过运行这个测试单元,可以对某个问题进行验证。

  • TestSuite

    就是多个测试用例的集合,而且TestSuit之间可以互相嵌套。

    • TestLoader用来加载TestCase到TestSuite中,其中有几个loadTestsFrom__()方法,就是从各个地方寻找TestCase,创建它们的实例,然后add到TestSuite中,再返回一个TestSuit实例。
  • TextTestRunner是用来执行测试用例的,其中的run(test)会执行TestSuit/TestCase中的run(result)方法。

    测试结果会保存到TextTestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息。

  • 使用fixture来堆测试用例环境进行搭建和摧毁。

代码实例

test_func.py

def add(a,b):
return a + b

def minus(a,b):
return a - b

def multi(a,b):
return a*b

def divide(a,b):
return a/b

tese_func.py

import unittest # 导入unittest模块
from week4.unit1.test_func import *

class TestFunc(unittest.TestCase): # 测试用例
'''test test_func.py'''

每个测试方法均以test开头,否则是不被unittest识别的。

def test_add(self):
'''test method add(a,b)'''
self.assertEqual(3,add(1,2))
self.assertNotEqual(2,add(2,2))
def test_minus(self):
'''test method minus(a,b)'''
self.assertEqual(1,minus(3,2))
def test_multi(self):
'''test method multi(a,b)'''
self.assertEqual(6,multi(2,3))
def test_divide(self):
'''test method divide(a,b)'''
self.assertEqual(2,divide(6,3))
self.assertEqual(2.5, divide(5,2))
if name == "main":
unittest.main()

代码中,TestFunc就是一个测试用例,测试用例每有一个test开头的方法,再load的时候便会生成一个TestCase实例。

之后我们通过TestLoader加载TestCase到TestSuite,用TextTestRunner来运行TestSuite。运行结果保存再TestTestResult中,我们通过命令行或者unittest.main()执行时,main会调用到TextTestRunner中的run来执行,

或者我们可以通过直接使用TextTestRunner来执行用例。

再Runner执行时,默认将执行结果说出到控制台,但是我们可以设置输出到其它文件,再文件中查看结果。(HTMLTestRunner,通过它可以将结果输出到HTML中,生成较为漂亮的报告)

TestSuite

通过该方法来控制用例的执行,添加到TestSuite中的case会按照添加的顺序执行。

还可以再Test Suite中添加多个测试文件,

代码实例:

import unittest
from test_func import TestFunc

if name == "main":
suite = unittest.TestSuite()
tests = [TestFunc("test_add), TestFunc("test_minus"), TestFunc("test_divide")]
suite.addTests(tests)

runner = unittest.TextTestRunner(verbosity = 2)
runner.run(suite)

通过下面的方法也可以传入测试用例

# 添加单个TestCase
suite.addTest(TestCalculateFunc("test_multi")) # 注意,是addTest,不是addTests,留神s的区别

通过使用loadTestFromName() 括号内传入"模块名.TestCase名"

suite.addTests(unittest.TestLoader().loadTestsFromName("test_func.TestFunc")) # 添加单个
suite.addTests(unittest.TestLoader().loadTestsFromNames([test_func.TestFunc])) # 添加多,注意s和中括号的差别

通过使用loadTestsFromTestCase() 传入TestCase

suite.addTests(unittest.TestLoader().loadTestFromTestCase(TestFunc))
runner = unittes.TextTestRunner(verbosity = 2) # verbosity = 1 是打印的报告不如2的详细。
runner.run(suite)

注意: 用TestLoader无法对case进行排序

将测试结果写入文件

可以将测试结果写入文件,生成测试报告,对模块质量提供依据。

代码实例:

if name == "main":
suit = unittest.TestSuite()
suite.addTests(unittest.TestLoader().loadTestFromTestCase(TestCalculateFunc))
with open("UnittestTestReport.txt","a") as f:
runner = unittest.TextTestRunner(stream = f, verbosity = 2) # 将测试报告写入文件,可以设置verbosity
runner.run(suite)

unittest中的参数化

首先需要安装nose_parameterized模块 pip instuall nose_parameterized

方法模块:

def login(username,password):
if username == "Eric" and password == "123456":
return True
else:
return False

测试套件模块:

from parameterized import parameterized

class TestCalculateFunc(unittest.TestCase):
'''test func.py'''

num = 1

@parameterized.expand([
["eric", "123456", True], # 可以是list,也可以是元组
["", "123456", True],
["eric", "12345", True],
["lingling", "123456"]
])

测试用例模块

def test_login(self, username, password, flag):

这里的参数对应上述列表里的元素,运行时会遍历上述二维列表

''' 登录 '''
res = login(username,password)
self.assertEqual(res,flag)

setUp() , tearDown()

setUp() 和tearDown()两个方法(本质上是重写了TestCase的这两个方法),

这两个方法在每个测试方法执行前以及执行后执行一次,setUp用来为测试准备环境,tearDown用来清理环境,为之后的测试做准备。

代码实例:

def setUp(self):
print("do something before test.Prepare environment")

def tearDown(self):
print("do something after test.Clean up")

这两个方法要写在测试用例里面。如果想要在每个case执行时只各自执行一次,为了达到这样的效果,我们可以把这两个方法设置为类方法。

setUpClass() 和 tearDownClass()再给它们加上类修饰符修饰。

代码实例:

class TestCalculateFunc(unittest.TestCase):
@classmethod
def setUpClass(cls): # 注意,此时为setUpClass(), 不是setUp()
print("do something before test.Prepare environment")

@classmethod
def tearDownClass(cls):
print("do something after test.Clean up")
"""Test calculate_func.py"""

跳过case

  1. skip装饰器

    @unittest.skip("I don't want to run this case")
    def test_divides(self):
    ···

    skip装饰器一共有三个:

    1. unittest.skip(reason)

    2. unittest.skiplf(condition,reason)

    3. unittest.skipUnless(condition,reason)

    skip无条件跳过

    skipif是当condition为True时跳过(只有当条件满足时才跳过)

    skipUnless是当condition为False时跳过(只有当条件满足时才不跳过)

HTMLTestRunner ——输出漂亮的报告

通过下载报告库即可使用

HTMLTestRunner是一个第三方的unittest HTML报告库,首先我们下载HTMLTestRunner.py,并放到当前目录下,或者你的’C:\Python27\Lib’下,就可以导入运行了。

下载地址:

官方原版

修改版

[Python3.x版本

总结

  • unittest是python自带的单元测试框架,以后写单元测试时可以拿来用。

  • unittest的流程:

    要被测试的方法==>测试用例==》测试套装==》执行

  • 当class继承unittest.TestCase后就会变成一个TestCase,其中以test开头的方法再load时会被加载为一个真正的TestCase

  • verbosity可以控制测试报告输出的样式,1为一般报告,2为详细报告

  • 可以通过addTest和addTests向suite中添加case或suite,可以使用TestLoader的loadTestForm()方法

  • 可以使用setUp(),tearDown(), setUpClass(), tearDownClass()来进行用例执行前的环境布置和执行后的环境清理。

  • 可以使用skip,skipIf, skipUnless装饰器跳过某个case。或者使用TestCase.skipTest()

  • 再输出方法unittest.TextTestRunner(verbosity=2)中添加stream可以将报告输出到文件。TextTestRunner输出txt报告,HTMLTestRunner输出html报告。

你可能感兴趣的:(2018-08-07(16)单元测试(下))