zoukankan      html  css  js  c++  java
  • 单元测试

    一.单元测试的定义

    1.什么是单元测试?

    单元测试就是对单个模块或者是单个类或者是单个函数进行测试;一般是开发做的,按照测试阶段来分,一般是单元测试、集成测试、系统测试、验收测试。

    2.为什么需要做单元测试?

    1)单元测试之后,才是集成测试。单个单个功能模块测试通过之后,才能将单个功能模块集成起来做集成测试。为了从底层发现bug,减少模块合成之后出现的问题。

    2)越早发现bug越好,这样可以早点发现问题,不然等问题积累到后面,如果做错了就要推倒重来,对于时间和经费来说,也是非常的浪费。

    对于我们测试来说:我们就单元测试是为了执行测试用例的。

    输入测试数据——>输出测试结果

    二.unittest框架以及原理介绍

    1.unittset框架最核心的四个概念:

    • TestCase:一个testcase的实例就是一个测试用例
    • TestSuite:多个测试用例集合在一起。TestLoader:是用来把TestCase加载到TestSuite中的。
    • TextTestRunner:用来执行测试用例的。
    • fixture:测试用例环境的搭建和销毁,测试前准备环境的搭建(setUp),执行测试代码(run),以及测试后环境的还原(tearDown)。

    2.单元测试案例

    • 测试需求一

    def login_chek(username,password):
      """
      登录校验的函数
      :param username:账号
      :param password:密码
      :return:
      """ if 6 <= len(password) <= 18: if username == 'python18' and password == 123456: return {'code':'0000','massage':'账户密码正确,登陆成功'} else: return {'code':'0001','massage':'账户或者密码不正确,登陆失败'} else: return {'code': '0001', 'massage': '密码长度必须在6-18位之间'}
    • 设计用例测试上面的登陆校验是否正常?

      """

      1、账户、密码正确-----{'code':'0000','massage':'账户密码正确,登陆成功'}

      2、账户正确,密码在6-18之间,密码不正确-----{'code':'0001','massage':'账户或者密码不正确,登陆失败'}

      3、账户正确,密码少于6位-----{'code': '0001', 'massage': '密码长度必须在6-18位之间'}

      4、账户正确,密码长度大于18位----{'code': '0001', 'massage': '密码长度必须在6-18位之间'}

      5、账户错误,密码正确-----{'code':'0001','massage':'账户或者密码不正确,登陆失败'}

      """

    三.编写测试用例

    1.TestCase类编写测试用例

          继承unittest里面的TestCase类,继承这个类,写能写测试用例,每个测试用例我们都要记得引入fixture,做一些准备以及结束的工作。

    编写测试用例步骤如下:

    1)导入unittest模块、被测文件或者其中的类(import unittest)

    2)创建一个测试类,并继承unittest.TestCase,继承父类(unittest.TestCase)的属性与方法。

    3)重写setUp和tearDown方法(如果有初始化条件和结束条件)

    4)定义测试函数、函数名以test开头。测试用例

    5)调用unittest.main()方法进行测试用例。

    import unittest
    from pack import login_check
    
    # 继承unittest的TestCase类
    class LoginTest(unittest.TestCase): 
        def setUp(self):
            print("执行每一条测试用例之前都会执行这个方法,可以使用该方法,做测试之前的环境准备工作")
        def tearDown(self):
            print("执行完每一条测试用例之后都会执行该方法,可以使用该方法来恢复环境")
    
        # 一个测试用例就是该类中的一个方法。测试用例的方法必须要以test开头
        # 正常的测试用例(账号、密码正确,登录成功)
        def test_login(self): 
         # 预期结果 
            excepted = {'code':'0000','massage':'账户密码正确,登陆成功'}
         # 传入参数
            data = ('python18','123456') 
            # 调用被测函数,传入参数(需要解包),获取实际结果   
            res = login_check(*data)
            try:
                self.assertEqual(excepted,res)  # 通过实例对象(self)来调用assertEqual()方法
            except AssertionError as e:
                print("该测试用例测试未通过")      # 可通过异常捕获来获取
                raise e                         # 此处需要使用raise主动抛出异常
            else:
                print("该测试用例测试通过")
    
      # 异常用例(账户错误,密码正确)
        def test_username_error(self):
            excepted = {'code':'0001','massage':'账户或者密码不正确,登陆失败'}
            data = ('java','123456')
            res = login_check(*data)
            try:
                self.assertEqual(excepted,res)
            except AssertionError as e:
                print("该测试用例测试未通过")  # 可通过异常捕获来获取
                raise e                     # 此处需要使用raise主动抛出异常
            else:
                print("该测试用例测试通过")
    
      # 异常用例(账户正确,密码在6-18位,密码错误)
        def test_password_error(self):
            excepted = {'code':'0001','massage':'账户或者密码不正确,登陆失败'}
            data = ('python','112233')
            res = login_check(*data)
            try:
                self.assertEqual(excepted,res)
            except AssertionError as e:
                print("该条测试用例测试未通过")
                raise e
            else:
                print("该条测试用例测试通过")
    
        # 异常用例(账户正确,密码少于6位)
        def test_password_lt6(self):
            excepted = {'code': '0001', 'massage': '密码长度必须在6-18位之间'}
            data = ('python','1238777')
            res = login_check(*data)
            try:
                self.assertEqual(excepted,res)
            except AssertionError as e:
                print("该条测试用例测试未通过")
                raise e
            else:
                print("该条测试用例测试通过")
    
      # 异常用例(账户正确,密码长度大于18位)
        def test_password_gt18(self):
            excepted = {'code': '0001', 'massage': '密码长度必须在6-18位之间'}
            data = ('python','12333444455534343441675')
            res = login_check(*data)
            try:
                self.assertEqual(excepted,res)
            except AssertionError as e:
                print("该条测试用例测试未通过")
                raise e
            else:
                print("该条测试用例测试通过")

    四.测试集合

    1.TestSuite&TestLoader的使用

    TestSuite:测试集,把所有测试用例都存进来。常用的方法如下:

    unittest.TestSuite()

    方法一:addTest() 添加一个测试用例

    方法二:addTest([,,,,]) 添加多个测试用例 添加用例的方式都是一样的。

    unittest.TsetLoader()

    方法三:unittest.TestLoader.loadTestFromModule(模块名)不需要加引号(注意要导入模块)

    方法四:unittest.TestLoaderTestsFromTestCase(测试类名)不需要加引号

    2.总结和疑问

    1.定义的测试类和测试套件写在不同的模块里,为什么?

    2.为何引入测试集,方便批量进行单元测试。

    完整的单元测试很少只执行一个测试用例,开发人员通常需要编写多个测试用例才能对某个软件功能进行比较完整的测试,这些相关的测试用例被称为测试用例集,用TestSuite类来表示的,用到的是TestSuite(),用addTest

    import unittest
    from pack.python13 import LoginTest
    from pack import python13
    
    # 创建一个测试集合
    suite = unittest.TestSuite()
    
    # 添加测试用例
    # 第一种 单个用例添加:接收的参数是测试用例的对象
    suite.addTest(LoginTest('test_login'))
    suite.addTest(LoginTest('test_username_error'))
    suite.addTest(LoginTest('test_password_lt6'))
    # 第二种 一次添加多条测试用例
    suite.addTests([LoginTest('test_login'),LoginTest('test_username_error'),LoginTest('test_password_lt6')])
    # 第三种 一次添加一个测试用例类(类名不需要加引号)
    loader = unittest.TestLoader()
    suite.addTest(loader.loadTestsFromTestCase(LoginTest))   # 需要先将LoginTest类导进来
    # 第四种 通过模块去添加
    loader = unittest.TestLoader()
    suite.addTest(loader.loadTestsFromModule(python13))
    
    # 运行测试集合
    # 创建一个runner对象
    runner = unittest.TextTestRunner()
    runner.run(suite)                     # 执行测试套件
    

      

    五.unittest断言介绍

    断言方法

    方法检查
    assertEqual(a,b) a == b (判断两个值是否相等)
    assertNotEqual(a,b) a != b (判断两个值是否不相等)
    assertTrue(x) bool(x) is True (判断对象的布尔值x是否为True)
    assertFalse(x) bool(x) is False (判断对象的布尔值x是否为False)
    assertIs(a,b) a is b(判断a和b是否是同一对象)
    assertIsNot(a,b) a is not b
    assertIn(a,b) a in b
    assertNotIn(a,b) a not in b

    六.执行用例&生成报告

    需要将 HTMLTestRunnerNew  测试报告模板文件复制至site-packages目录下。

    1.TextTestRunner的用法

    1. 测试用例已经集合完毕,如何来执行测试用例?

      需要用到TextTestRunner,执行测试集合,用到的是TextTestRunner(),用run方法。

      #创建runner对象
      runner = unittest.TextTestRunner()
      #这里将传入测试集合进行执行
      runner.run(suite)

    2. 测试结果怎么看?

    • . 代表测试用例通过 一个点代表一个测试用例
    • E 代表测试用例执行出错了
    • F 代表测试用例不通过

    3.生成测试报告

    # 新建一个register_report.py文件
    import unittest
    from python.register_testcase import RegisterTest
    from HTMLTestRunnerNew import HTMLTestRunner
    
    # 创建一个测试集合
    suite = unittest.TestSuite()
    # 将测试用例加载到测试集合
    loader = unittest.TestLoader()
    suite.addTest(loader.loadTestsFromTestCase(RegisterTest))
    
    # 1、执行测试(套件)集合,并生成文本格式的测试报告
    with open("report.txt","w",encoding='utf-8') as f:   # 报告内容过于鸡肋,几乎不用
         runner = unittest.TextTestRunner(f)
         runner.run(suite)
    
    # 2、执行测试(套件)集合,并生成HTML格式的测试报告
    with open('report.html','w') as f:
        runner = HTMLTestRunner(stream=f,     # 需要写入的文件名
                                verbosity=2,  # 写入的等级,2是最高级的,也是最详细的
                                title ='python_test_rerport',  # 报告的名称
                                description='这是pytest单元测试的一份测试报告',  # 报告的相关描述
                                tester='WL')    # 测试者姓名
        runner.run(suite)
    

      

  • 相关阅读:
    关于分析web.xml的一篇博客,写的很详细
    (转)Java编译后产生class文件的命名规则
    Standard 1.1.x VM与Standard VM的区别
    throws和throw的用法例子以及检测和非检查异常
    终端IO(上)
    [APUE]进程关系(下)
    [APUE]进程关系(上)
    [APUE]进程控制(下)
    [APUE]进程控制(中)
    深究标准IO的缓存
  • 原文地址:https://www.cnblogs.com/wanglle/p/11448798.html
Copyright © 2011-2022 走看看