python自带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提供断言

最常用的断言方式

methodchecks thatdescriptionNew 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