51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

查看: 523|回复: 0
打印 上一主题 下一主题

[转贴] Unittest单元测试框架基础知识

[复制链接]
  • TA的每日心情
    无聊
    前天 09:14
  • 签到天数: 938 天

    连续签到: 5 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2022-7-19 09:42:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    一 、unittest模块的属性介绍
      UnitTest:
        在Python自动化领域有两个绕不开的测试框架,分别是UnitTest和PyTest
        UnitTest本身是单元测试框架,截止到目前,已经可以基于此框架来实现Selenium、Appium、Requests接口自动化
        UnitTest已经默认安装在python环境中了,不需要再额外进行安装
      四大特性:
        1.前置与后置,Setup和Teardown
        2.测试用例,所有的用例都是基于TestCase类来实现的
        3.测试套件与运行器,可以精细化管理测试用例以及生成测试报告
        4.断言机制,封装了很多断言,可以直接通过self.来调用所有已封装好的断言函数
      1.1 unittest的属性如下:
    1.  ['BaseTestSuite', 'FunctionTestCase', 'SkipTest', 'TestCase', 'TestLoader', 'TestProgram', 'TestResult', 'TestSuite', 'TextTestResult', 'TextTestRunner',? 'case', 'defaultTestLoader', 'expectedFailure', 'findTestCases', 'getTestCaseNames', 'installHandler', 'loader', 'main', 'makeSuite', 'registerResult', 'removeHandler', 'removeResult', 'result', 'runner', 'signals', 'skip', 'skipIf', 'skipUnless', 'suite', 'util']
    复制代码
     1.2 常用属性介绍
      unittest.TestCase:TestCase类,所有测试用例类继承的基本类,该类下所有以test开头的函数都是测试用例
    1. class BaiduTest(unittest.TestCase):
    2.     pass
    3.     
    4.      def test_case1(self):
    5.        pass
    复制代码
    unittest.main():使用她可以方便的将一个单元测试模块变为可直接运行的测试脚本,main()方法使用TestLoader类来搜索所有包含在该模块中以“test”命名开头的测试方法,并自动执行他们。执行方法的默认顺序是:根据ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z。所以以A开头的测试用例方法会优先执行,以a开头会后执行。
      unittest.TestSuite():unittest框架的TestSuite()类是用来创建测试套件的,即多个测试用例的集合。
      unittest.TextTextRunner():unittest框架的TextTextRunner()类,通过该类下面的run()方法来运行suite所组装的测试用例,入参为suite测试套件。
      unittest.defaultTestLoader():?defaultTestLoader()类,通过该类下面的discover()方法可自动根据测试目录start_dir匹配查找测试用例文件(test*.py),并将查找到的测试用例组装到测试套件,因此可以直接通过run()方法执行discover。用法如下:
    1.   discover=unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')
    复制代码
    unittest.skip():装饰器,当运行用例时,有些用例可能不想执行等,可用装饰器暂时屏蔽该条测试用例。一种常见的用法就是比如说想调试某一个测试用例,想先屏蔽其他用例就可以用装饰器屏蔽。
      @unittest.skip(‘跳过原因’)装饰器:无条件跳过装饰的测试,并说明跳过测试的原因。
      @unittest.skipIf('条件',‘跳过原因’)装饰器:条件为真时,跳过装饰的测试,并说明跳过测试的原因。
      @unittest.skipUnless('条件',‘跳过原因’)装饰器:条件为假时,跳过装饰的测试,并说明跳过测试的原因。
      @unittest.expectedFailure:预言会失败,先执行,如果失败不会报错,会忽略这个测试用例,和跳过的差别在于跳过不执行用例,这个是执行用例失败后跳过
      二、各属性详细介绍
      1.TestCase类的常用属性
      setUp():setUp()方法用于测试用例执行前的初始化工作。如测试用例中需要访问数据库,可以在setUp中建立数据库连接并进行初始化。如测试用例需要登录web,可以先实例化浏览器
      tearDown():tearDown()方法用于测试用例执行之后的善后工作。如关闭数据库连接。关闭浏览器。
      assert*():一些断言方法:在执行测试用例的过程中,最终用例是否执行通过,是通过判断测试得到的实际结果和预期结果是否相等决定的。
    1. assertEqual(a,b,[msg='测试失败时打印的信息']):断言a和b是否相等,相等则测试用例通过。
    2.   assertNotEqual(a,b,[msg='测试失败时打印的信息']):断言a和b是否相等,不相等则测试用例通过。
    3.   assertTrue(x,[msg='测试失败时打印的信息']):断言x是否True,是True则测试用例通过。
    4.   assertFalse(x,[msg='测试失败时打印的信息']):断言x是否False,是False则测试用例通过。
    5.   assertIs(a,b,[msg='测试失败时打印的信息']):断言a是否是b,是则测试用例通过。
    6.   assertNotIs(a,b,[msg='测试失败时打印的信息']):断言a是否是b,不是则测试用例通过。
    7.   assertIsNone(x,[msg='测试失败时打印的信息']):断言x是否None,是None则测试用例通过。
    8.   assertIsNotNone(x,[msg='测试失败时打印的信息']):断言x是否None,不是None则测试用例通过。
    9.   assertIn(a,b,[msg='测试失败时打印的信息']):断言a是否在b中,在b中则测试用例通过。
    10.   assertNotIn(a,b,[msg='测试失败时打印的信息']):断言a是否在b中,不在b中则测试用例通过。
    11.   assertIsInstance(a,b,[msg='测试失败时打印的信息']):断言a是是b的一个实例,是则测试用例通过。
    12.   assertNotIsInstance(a,b,[msg='测试失败时打印的信息']):断言a是是b的一个实例,不是则测试用例通过。
    复制代码
    2.TestSuite类的常用属性(组织用例时需要用到,配合TextTextRunner)
      [ 'addTest', 'addTests', 'countTestCases', 'debug', 'run']
      说明:
      addTest():?addTest()方法是将测试用例添加到测试套件中,如下方,是将test_baidu模块下的BaiduTest类下的test_baidu测试用例添加到测试套件。
    1. suite = unittest.TestSuite()
    2.   suite.addTest(test_baidu.BaiduTest('test_baidu'))
    复制代码
    3.TextTextRunner的属性如下:(组织用例时需要用到,配合TestSuite)
      [' 'buffer', 'descriptions', 'failfast', 'resultclass', 'run', 'stream', 'verbosity']
      说明:
      run(): run()方法是运行测试套件的测试用例,入参为suite测试套件。
    1.  runner = unittest.TextTestRunner()
    2.   runner.run(suite)
    复制代码
    三、unittest基本使用
      3.1 基本用法
      以下以selenium操作谷歌浏览器打开网页为例,讲解unittest的用法
      将selenium访问谷歌的线性代码简单封装得到web_key_demo逻辑代码,基于封装好的逻辑代码,可以引入unittest来管理多个测试用例:
    1.  import time
    2.   from selenium import webdriver
    3.   """
    4.   关键字驱动类:底层逻辑代码,这个类不会直接执行测试行为。
    5.   属于逻辑层代码,常规的操作行为封装成自定义的关键字函数。
    6.   在执行自动化的时候,通过调用自定义函数类,来实现自动化测试操作。
    7.   常规操作行为:
    8.   1.创建浏览器对象
    9.   2.访问url
    10.   3.元素定位
    11.   4.输入
    12.   5.点击
    13.   6.其他...
    14.   """
    15.   #基于type生成对应的浏览器对象
    16.   def browser(type_):
    17.       try:
    18.           # driver本身只限于webdriver对象
    19.           driver = getattr(webdriver,type_)()
    20.       except Exception as e:
    21.           driver = webdriver.Chrome()
    22.       return driver
    23.   class KeyDemo:
    24.       def __init__(self, type_):
    25.           self.driver = browser(type_)
    26.       #访问url
    27.       def open(self,url):
    28.           self.driver.get(url)
    29.       #元素定位:8种元素定位
    30.       def locator(self,name,value):
    31.           return self.driver.find_element(name,value)
    32.       #输入
    33.       def input(self, name,value,txt):
    34.           self.locator(name, value).send_keys(txt)
    35.       #点击
    36.       def click(self, name,value):
    37.           self.locator(name,value).click()
    38.       #关闭浏览器
    39.       def quit(self):
    40.           self.driver.quit()
    41.       def sleep(self,time_):
    42.           time.sleep(time_)
    复制代码
    web_key_demo
      使用unittest编写python的单元测试代码,包括如下几个步骤:
      1、编写一个python类,继承 unittest模块中的TestCase类,这就是一个测试类
      2、在上面编写的测试类中定义测试方法(这个就是指的测试用例),每个方法的方法名要求以 test 打头,没有额外的参数。 在该测试方法中 调用被测试代码,校验测试结果,TestCase类中提供了很多标准的校验方法,如 最常见的assertEqual。
      3、执行 unittest.main() ,该函数会负责运行测试,它会实例化所有TestCase的子类,并运行其中所有以test打头的方法
    1. import unittest # python自带,不需要额外安装
    2.   from web_key_demo import KeyDemo
    3.   class CaseDemo(unittest.TestCase):
    4.       # 在每个测试用例执行前先执行
    5.       def setUp(self) -> None:
    6.           self.kd = KeyDemo('Chrome')
    7.       # 每个测试用例执行后紧接着执行
    8.       def tearDown(self) -> None:
    9.           self.kd.quit()
    10.       def test_01(self): # 测试用例名字需要以test开头
    11.           self.kd.open(' http://www.baidu.com ')
    12.           self.kd.input('id', 'kw', '美女')
    13.           self.kd.click('id', 'su')
    14.           self.kd.sleep(3)
    15.       def test_02(self):
    16.           self.kd = KeyDemo('Chrome')
    17.           self.kd.open(' http://www.baidu.com ')
    18.           self.kd.input('id', 'kw', '妹子')
    19.           self.kd.click('id', 'su')
    20.           self.kd.sleep(3)
    21.       def test_03(self):
    22.           pass
    23.   if __name__ == '__main__':
    24.       # 执行该脚本执行所有的以test开头的测试用例,执行顺序为默认的顺序:
    25.           # setUp -- test_01 -- tearDown
    26.           # setUp -- test_02 -- tearDown
    27.           # setUp -- test_03 -- tearDown
    28.       unittest.main()
    复制代码
    3.2 断言、跳过、预言失败
     import unittest # python自带,不需要额外安装
      from ddt import ddt,data,file_data,unpack # 需要 pip install ddt
      @ddt # 装饰ddt来声明我要用这个ddt来管理测试类
      class CaseDemo(unittest.TestCase):
          # 如果希望从外边向测试用例类传参,就需要调用父类的init,从源码可以看到父类只有methodName='runTest'这么一个参数
          def __init__(self, methodName='runTest',wechat=None):
              super().__init__(methodName=methodName)
              self.wechat = wechat
          # 在测试用例执行前先执行
          def setUp(self) -> None:
              # self.kd = KeyDemo('Chrome')
              # print(self.wechat)
              print('+++++++++++++++++++++++++++++++++++')
              pass
          # 测试用例执行后紧接着执行
          def tearDown(self) -> None:
              # self.kd.quit()
              print('------------------------------------')
              pass
          # ======================================================= 跳过 ====================================================
          @unittest.skip('我无条件跳过,就无条件跳过')
          def test_skip1(self):
              print('我还有机会BB么??')
          @unittest.skipUnless(1>2, '判断结果为False,我就跳过')
          def test_skip2(self):
              print('我还有机会BB么??')
          @unittest.skipIf(1<2, '判断结果为True,我就跳过')
          def test_skip3(self):
              print('我还有机会BB么??')
          # ======================================================= 预言失败 ================================================
          # 预言失败:先执行,如果失败不会报错,会忽略这个测试用例,和跳过的差别在于跳过不执行用例,这个是执行用例失败后跳过
          @unittest.expectedFailure
          def test_aa(self):
              pass
              self.assertEqual(123, 321, msg='果然失败了')
          # ======================================================= 断言 ====================================================
          def test_assert(self):
              """'断言测试,msg是断言失败后提示信息,可以不要'
              """
              def _test():
                  return '老王'
              res = _test()
              # 各种断言的方法都是内置属性,可以选择合适的来用
              self.assertEqual(res,'老赵', msg=f'不是老赵干的别冤枉他,是{res}干的') # 断言value1 == value2
              # # 失败后返回 AssertionError: '老王' not found in ['老张', '老李'] : 老王不在嫌疑人里面里面,不是他
              # self.assertIn(res,['老张','老李'],msg=f'{res}不在嫌疑人里面里面,不是他')
              # # 失败后返回: '老王' is not false : 返回不是False
              # self.assertFalse(res,msg='返回不是False')
      if __name__ == '__main__':
          unittest.main()

    3.3 测试用例找不到报错
      注意执行的时候光标不能放入CaseDemo类中,需要放到外面,点一下其他位置再执行,不然会报错。
      AttributeError: type object 'CaseDemo' has no attribute 'test_01'
    1. Error
    2.   Traceback (most recent call last):
    3.     File "E:\python3.8\lib\unittest\case.py", line 60, in testPartExecutor
    4.       yield
    5.     File "E:\python3.8\lib\unittest\case.py", line 676, in run
    6.       self._callTestMethod(testMethod)
    7.     File "E:\python3.8\lib\unittest\case.py", line 633, in _callTestMethod
    8.       method()
    9.     File "E:\python3.8\lib\unittest\loader.py", line 34, in testFailure
    10.       raise self._exception
    11.     File "E:\python3.8\lib\unittest\loader.py", line 169, in loadTestsFromName
    12.       parent, obj = obj, getattr(obj, part)
    13.   AttributeError: type object 'CaseDemo' has no attribute 'test_01'
    复制代码











    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-4-28 02:42 , Processed in 0.064244 second(s), 23 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表