unittest框架

unittest

unittest是python中内置的单元测试框架(框架),不仅可以完成单元测试,也是适用于web自动化测试中。

unittest提供了丰富的断言方法,判断测试用例是否通过,然后生成测试报告

M:\tests\  # 我的是M盘的tests目录,所有操作都在tests目录内完成
    ├─discover   
    │  ├─son
    │  │  ├─test_dict.py 
    │  │  └─__init__.py
    │  ├─test_list.py
    │  ├─test_str.py
    │  └─__init__.py
    ├─loadTestsFromTestCaseDemo
    │  └─loadTestsFromTestCaseDemo.py
    ├─case_set.py   #用例集
    ├─myMain.py   # 代码演示文件,所有演示脚本文件
    ├─test_tuple.py
    └─__init__.py

目前这些文件都是空的,后续会一一建立,各目录内的init.py也必须建立,虽然他们都是空的,但是他无比重要,因为标明他所在目录是python的包

case_set.py有四个函数,分别计算加减乘除,并且,代码不变

"""
用例集
"""
def add(x,y):
    """
    两数相加
    :param x:
    :param y:
    :return:
    """
    return x + y

def sub(x,y):
"""
两数相减
:param x:
:param y:
:return:
"""

def mul(x,y):
"""
两数相乘
:param x:
:param y:
:return:
"""
return x*y

def div(x,y):
"""
两数相除
:param x:
:param y:
:return:
"""
return x / y

基础运行unittest

在myMain.py中

import case_set   #导入用例集
import unittest   #导入unittest框架

class myUnitTest(unittest.TestCase):

def setUp(self):
    """用例初始化"""
    print("用例初始化 setup")

def runTest(self):
    """执行用例"""
    print(case_set.add(2,3) == 5)

def tearDown(self):
    print("用例执行完毕,收尾")

if name == "main":
demo = myUnitTest()
demo.run() #固定的调用方法run

运行myMain.py,并且用例执行通过

用例执行流程:

setup首先在用例之前执行

接着执行用例,用例返回True

最后执行,teardown

在每个用例执行时,setup和teardown都会执行

注意:

myUnittest类名可以自定义,但是必须继承unittest.TestCase

示例中的setup和tearDown方法名是固定的,但如果,我们测试时,没有初始化和收尾的工作,setup和teardown方法可以忽略不写

至于执行用例的那个runTest方法名叫什么取决于在实例化myUniTest类时,我们来看unitest.TestCase类的init方法和run方法做了什么

class TestCase(object):
def __init__(self, methodName='runTest'):
    self._testMethodName = methodName
    self._outcome = None
    self._testMethodDoc = 'No test'  # 也请留意这个鬼东西 No test

def run(self, result=None):
    # run方法反射了methodName
    testMethod = getattr(self, self._testMethodName)
    #查找在这个类中有没有这个方法名

所以,runTest方法名可以自定义:

import unittest
import case_set

class myUnitTest(unittest.TestCase):

def add_test(self):
    """ 执行用例 """
    print(case_set.add(2, 3) == 5)

if name == 'main':
demo = myUnitTest(methodName='add_test')
demo.run()

unittest如何执行多用例

类的写法

import unittest
import case_set

class myUnitTestAdd(unittest.TestCase):

def runTest(self):
    """ 执行用例 """
    print(case_set.add(2, 3) == 5)

class myUnitTestSub(unittest.TestCase):

def runTest(self):
    """ 执行用例 """
    print(case_set.sub(2, 3) == 5)  # 用例结果不符合预期

if name == 'main':
demo1 = myUnitTestAdd()
demo2 = myUnitTestSub()
demo1.run()
demo2.run()

类方法的写法:

import unittest
import case_set

class myUnitTest(unittest.TestCase):

def add_test(self):
    """ 执行用例 """
    print(case_set.add(2, 3) == 5)

def sub_test(self):
    """ 执行用例"""
    print(case_set.sub(10, 5) == 2)

if name == 'main':
demo1 = myUnitTest('add_test')
demo2 = myUnitTest('sub_test')
demo1.run()
demo2.run()

上面方式,每个用例都要实例化一次,虽然可以执行多个用例,但是,这么写太low,反倒没有测试触发用例来的简单。另外,用print打印也不符合真实的测试环境

我们先来解决print的问题

使用unittest提供断言

最常用的断言方式

method checks that description New in
assertEqual(a,b,msg) a==b 如果a不等于b,断言失败  
assertNotEqual(a,b,msg) a!=b 如果a等于b,断言失败  
assertTrue(x,msg) bool(x) is True 如果表达式x不为True,断言失败  
assertFalse(x,msg) bool(x) is False 如果表达式不为False,断言失败  
assertIs(a,b,msg) a is b 如果a is not b,断言失败  
assertIsNot(a,b,msg) a is not b 如果a is b,断言失败 3.1
assertIsNone(x,msg) x is not None 如果不是None,断言失败 3.1
assertIn(a,b,msg) a is b 如果a not in b,断言失败 3.1
assertNotIn(a,b.msg) a not in b 如果a in b,断言失败 3.1
assertIsInstance(a,b,msg) isinstance(a,b) 如果a不是b类型,断言失败 3.1
assertNotIsInstance(a,b.msg) not isinstance(a,b) 如果a是b类型,断言失败 3.1

unittest简单上手

# import unittest

class MyTestCase(unittest.TestCase):

def setUp(self):

print('初始化')

def tearDown(self):

print('收尾')

def xxxTest(self):

print(11111)

if name == 'main':

obj = MyTestCase(methodName='xxxTest')

obj.run()

unittest简单断言

# import requests
#
# url = 'https://cnodejs.org/api/v1/topics'
#
# class TestCase2(unittest.TestCase):
#
#     def setUp(self):
#         response = requests.get(url)
#         self.res = response.json()['success']
#
#     def test_case_01(self):
#
#         print(111111, self.res)
#         # self.assertEqual(False, res, msg='预期值{} 与期望值{} 不相符'.format(False, res))
#         self.assertTrue(self.res)
#
#
#     def test_case_02(self):
#         self.assertFalse(self.res)
#
# if __name__ == '__main__':
#     unittest.main()

unitest的TestSuite测试套件的使用

  1. 自己实例化用例对象
  2. 使用TestSuite创建容器
  3. 自己将用例对象添加到容器中
  4. 使用TestTestRunner执行容器中的用例

要执行的测试用例

import unittest

class TestCase1(unittest.TestCase):

def test_case_01(self):
    self.assertTrue(1)

def test_case_02(self):
    print(xxx)
    self.assertTrue(0)

def test_case_03(self):
    self.assertTrue(0)

if name == 'main':
# # 1. 实例化用例对象
# case1 = TestCase1('test_case_01')
# case2 = TestCase1('test_case_02')
# case3 = TestCase1('test_case_03')

创建测试套件(用例)

使用测试套件TestSuite

方式一:

    # # 2. 创建测试套件(容器)
    # suite_obj = unittest.TestSuite()
    # # suite_obj.addTest(case1)
    # # suite_obj.addTest(case2)
    unittest.TextTestRunner().run(suite_obj)

方式二:

    # # for i in [case1, case2]:
    # #     suite_obj.addTest(i)
    这种方式与上一种相同
    # suite_obj.addTests([case1, case2, case3])
    unittest.TextTestRunner().run(suite_obj)

方式三:

    # 1. 实例化用例对象
    # case1 = TestCase1('test_case_01')
    # case2 = TestCase1('test_case_02')
    # case3 = TestCase1('test_case_03')
    case = map(TestCase1, ['test_case_01', 'test_case_02', 'test_case_03'])
    # 2. 创建测试套件(容器)
    suite_obj = unittest.TestSuite()
    # suite_obj.addTest(case1)
    # suite_obj.addTest(case2)
# for i in [case1, case2]:
#     suite_obj.addTest(i)
suite_obj.addTests(case)
# 3. 找个执行器执行测试套件中的用例
unittest.TextTestRunner().run(suite_obj)

makeSuite的使用

import unittest

class TestCase2(unittest.TestCase):

def test_case_01(self):
    self.assertTrue(1)

def test_case_02(self):
    self.assertTrue(0)

def test_case_03(self):
    self.assertTrue(0)

def my_case_01(self):
    self.assertTrue(1)

def my_case_02(self):
    self.assertTrue(1)

if name == 'main':

suite = unittest.makeSuite(testCaseClass=TestCase2, prefix='test')
print(33333333, suite.countTestCases())
suite.addTests(map(TestCase2, ['my_case_01', 'my_case_02']))
print(4444, suite.countTestCases())

# 执行器
unittest.TextTestRunner().run(suite)

  1. 在创建容器时,该套件自动帮我们去指定的TestCaseClass类中获取以prefix开头的用例,器执行该容器中的一个容器对象

  2. 使用例用执行

    import unittest
    discover = unittest.TestLoader().discover(
        start_dir=base_dir,   # 该参必传
        pattern='test*.py',   # 保持默认即可。
        top_level_dir=None
        )
    unittest.TextTestRunner(verbosity=2).run(discover)
    

    该discover方法接收三个参数:

    start_dir:要测试的模块名或者测试用例的目录。

    pattern="test*.py":表示用例文件名的匹配原则,默认匹配以test开头的文件名,星号表示后续的多个字符。

    top_level_dir=None:测试模块的顶层目录,如果没有顶层目录,默认为None。

    注意:

    discover对给定的目录是有要求的,它Python的包,也就是目录有‘init.py’文件的才算是Python的包,只要是要读取的目录,都必须是包。

    关于start_dir和top_level_dir的几种情况:

    • start_dir目录可以单独指定,这个时候,让top_level_dir保持默认(None)即可。
    • start_dir == top_level_dir, start_dir目录与top_level_dir目录一致,discover寻找start_dir指定目录内的符合规则的模块。
    • start_dir < top_level_dir,start_dir目录是top_level_dir目录的子目录。discover寻找start_dir指定目录内的符合规则的模块。
    • start_dir > top_level_dir,start_dir目录如果大于top_level_dir目录,等待你的是报错AssertionError: Path must be within the project。说你指定的路径(start_dir)必须位于项目内(top_level_dir)。

 

 

 

unittest中类级别的setup和tearDown

class myUnitTest(unittest.TestCase):
# def test_sub(self):
#     self.assertEqual(10-5, 5)

def setUp(self):
    print(&#39;敌军还有三十秒到达战场, 碾碎他们....&#39;)

def test_add(self):
    print(3333333333333333333)
    self.assertEqual(2+3, 5)

def tearDown(self):
    # time.sleep(5)
    print(&#39;打完收工,阿sir出来洗地了.....&#39;)
#
@classmethod
def setUpClass(cls):
    print(&#39;在用例集开始执行,我去建立数据库连接......&#39;)

@classmethod
def tearDownClass(cls):
    print(&#39;全军撤退, 我收工.......&#39;)

if name == 'main':
unittest.main()

verbosity参数

import unittest

class TestStringMethods(unittest.TestCase):

def test_assertFalse(self):
    self.assertFalse(&#39;&#39;)

if name == 'main':
unittest.main(verbosity=1)

0是静默模式,简单的输出结果

1,静默模式,添加每个用例执行的结果,通过是 . ,失败是 F,报错是 E

2,详细模式,详细的输出,详细的输出每个用例的执行结果

unittest.skip

跳过的提示‘s’.

使用实例:

import unittest

class TestCase01(unittest.TestCase):

@unittest.skip(reason=&#39;跳过&#39;)
def test_case_01(self):
    self.assertTrue(1)

@unittest.skipIf(condition=1, reason=&#39;条件为真跳过用例&#39;)
def test_case_02(self):
    self.assertTrue(1)

if name == 'main':

unittest.main()

插件

unittest中的插件暂时不能使用pip
下载我们从网上下载:https://www.cnblogs.com/Neeo/articles/7942613.html

相关文章: