ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

一篇文章搞懂unittest单元测试框架

2021-12-22 14:01:53  阅读:175  来源: 互联网

标签:__ search driver unittest 单元测试 key 搞懂 self


在这里插入图片描述
Python 2.1及以后的版本,将unittest作为一个标准模块放入Python开发包中。

01 使用unittest编写测试用例

规则:

  • import unittest
  • 创建一个测试类,必须要继承unittest.TestCase类
  • 创建一个测试方法,且方法要以“test” 开头
from calculator import Calculator
    import unittest
     
    class TestAdd(unittest.TestCase):
        def test_add(self):
            c =Calculator(3,5)
            result = c.add()
            self.assertEqual(result,8)
     
    if __name__ =='__main__':
        unittest.main() //通过main()方法来执行测试用例;按照测试类、方法的名称ASCII值大小的顺序执行用例

unittest的执行结果:

  • “.” 表示测试用例执行通过
  • “F”表示执行失败
  • “E” 表示执行错误
  • "s“表示运行跳过

02 三个重要概念

  • Test Case

    最小的测试单元,即测试方法。

    unittest提供了TestCase基类,我们创建的测试类要继承该基类,它可以用来创建新的测试用例。

  • Test Suite

    测试用例、测试套件或两者的集合,用于组装一组要运行的测试。

    使用TestSuite类来创建测试套件。

  • Test Runner

    Test Runner是一个组件,用于协调测试的执行并向用户提供结果。

    unittest提供了TextTestRunner类运行测试用例。

03 测试用例执行顺序

unittest默认按照ASCII码的顺序加载测试用例(包括测试目录和测试文件、测试类、测试方法),即它并不是按照测试用例的创建顺序从上到下执行的。

discover() 和 main()方法的执行顺序是一样的。故想让某个测试文件先执行,可以在命名上加以控制。

如何控制测试用例的执行顺序?

可以通过TestSuite类的addTest()方法按照一定的顺序来加载测试用例,这样想先被执行的用例就可以先加载。

  from calculator import Calculator
    import unittest
     
    class TestAdd(unittest.TestCase):
        def test_add(self):
            c =Calculator(3,5)
            result = c.add()
            self.assertEqual(result,8)
     
        def test_add_decimals(self):
            c=Calculator(3.5,5.5)
            result=c.add()
            self.assertEqual(result,9)
     
    class TestSub(unittest.TestCase):
        def test_sub(self):
            c =Calculator(5,1)
            result = c.sub()
            self.assertEqual(result,4)
     
    if __name__ =='__main__':
        #创建测试套件
        suit = unittest.TestSuite()
        suit.addTest(TestSub("test_sub")) //添加测试用例
        suit.addTest(TestAdd("test_add_decimals"))
     
        #创建测试运行器
        runner = unittest.TextTestRunner()
        runner.run(suit)

04 执行多个测试用例

unittest.defaultTestLoader.discover()方法可以从多个文件中查找测试用例。

该类根据各种标准加载测试用例,并将它们返回给测试套件

discover(start_dir, pattern='Test*.py', top_level_dir=None)
  • start_dir:待测试的模块名/测试用例目录;

    discover()方法会自动根据这个参数查找测试用例文件

  • pattern:测试用例文件名的匹配原则

  • top_level_dir:测试模块的顶级目录,如果没有顶级目录,默认为None

import unittest
    test_dir='Test' //文件目录
     
    suits =unittest.defaultTestLoader.discover(test_dir, pattern='Test*.py')
     
    if __name__=='__main__':
        runner = unittest.TextTestRunner()
        runner.run(suits)

如果想让discover()查找子目录下的测试文件,得将子目录标记为一个python模块(子目录下放__init__.py文件)

05 跳过测试和预期失败

import  unittest
    class MyTest(unittest.TestCase):
     
        @unittest.skip("跳过这条用例")
        def test_skip(self):
            print('aaa')
     
        @unittest.skipIf(3>2,"当条件为真时跳过测试")
        def test_skip_if(self):
            print('bbb')
     
        @unittest.skipUnless(3>2,"当条件为假时跳过测试")
        def test_skip_unless(self):
            print('ccc')
     
    // 不论执行结果是什么,都将测试标记为失败
        @unittest.expectedFailure 
        def test_fail(self):
            print('ddd')
     
    if __name__=="__main__":
        unittest.main()

执行结果:

E:\selenium> & "D:/Program Files/Python39/python.exe" e:/selenium/Test/unittest/skip_fail.py
    ddd
    ussccc
    .
    ----------------------------------------------------------------------
    Ran 4 tests in 0.001s
     
    FAILED (skipped=2, unexpected successes=1)

以上四个装饰器同样适用于测试类。

06 Setup和Teardown

  • setUpModule/tearDownModule

    在整个模块的开始与结束时被执行

  • setUpClass/ tearDownClass

    在测试类的开始与结束时被执行

  • setUp/tearDown

    在测试用例的开始与结束时被执行

import unittest
    def setUpModule():
        print(" Module start .....")
     
    def tearDownModule():
        print(" Module end ...")
     
    class MyTest(unittest.TestCase):
     
        @classmethod
        def setUpClass(cls):
            print("Class Start...")
        
        @classmethod
        def tearDownClass(cls):
            print("Class end...")
     
        def setUp(self):
            print("test case start ...")
     
        def tearDown(self):
            print("test case end ...")
     
        def testcase1(self):
            print("this is first test case")
        
        def testcase2(self):
            print("this is second test case")
     
    if __name__ == "__main__":
        unittest.main()

执行结果如下:

E:\selenium> & "D:/Program Files/Python39/python.exe" e:/selenium/Test/unittest/setup.py
    Module start .....
    Class Start...
    test case start ...
    this is first test case
    test case end ...
    .test case start ...
    this is second test case
    test case end ...
    .Class end...
     Module end ...
     
 ----------------------------------------------------------------------
    Ran 2 tests in 0.002s
     
    OK

07 Web自动化测试

 import unittest
    from selenium import webdriver
    from time import sleep
     
    class Baidu(unittest.TestCase):
     
        @classmethod
        def setUpClass(cls):
            cls.driver = webdriver.Chrome()
            cls.driver.implicitly_wait(5)
            cls.driver.get("http://www.baidu.com")
            cls.driver.maximize_window()
        @classmethod
        def tearDownClass(cls):
            cls.driver.quit()
     
        def search(self,text):
            self.driver.find_element_by_id("kw").clear()
        self.driver.find_element_by_id("kw").send_keys(text)
            self.driver.find_element_by_id("su").click()
            sleep(3)
     
        def test_search_selenium(self):
            search_key="selenium"
            self.search(search_key)
            self.assertEqual(self.driver.title,search_key+"_百度搜索")
     
        def test_search_python(self):
            search_key="python"
            self.search(search_key)
            self.assertEqual(self.driver.title,search_key+"_百度搜索")
     
    if __name__ =="__main__":
        unittest.main()

08 Parameterized

Parameterized是python的一个参数化库,同时支持unittest、pytest单元测试框架。

  • pip install parameterized
  • parameterized.expand() 加载数据,列表中每个元组是一条测试用例
import unittest
    from time import sleep
    from selenium import webdriver
    from parameterized import parameterized
     
    class TestBaidu(unittest.TestCase):
        @classmethod
        def setUpClass(cls):
            cls.driver=webdriver.Chrome()
            cls.driver.get("http://www.baidu.com")
            cls.driver.maximize_window
     
        @classmethod
        def tearDownClass(cls):
            cls.driver.quit()
     
        def search(self,search_key):
            self.driver.find_element_by_id("kw").clear()
            self.driver.find_element_by_id("kw").send_keys(search_key)
            self.driver.find_element_by_id("su").click()
            sleep(5)
     
        @parameterized.expand(
            [
                ("case1","selenium"),
                ("case2","python")
            ]
        )
        def test_search(self,name,search_key):
            self.search(search_key)
            self.assertEqual(self.driver.title,search_key+"_百度搜索")
     
    if __name__ == '__main__':  
        unittest.main(verbosity=2)  

09 DDT

Data-Driven Tests 是针对unittest单元测试框架设计的扩展库。

安装:

pip install ddt

导入:

from ddt import ddt, data, file_data,unpack

使用规则:

  • 必须用 @ddt 装饰测试类
  • 数据有不同形式的参数化,如下方的元组、列表、字典类型
  • @data( 数据列表/元组/字典,字典的key和方法中的形参名称保持一致)
  • @unpack 装饰测试方法
import unittest
    from time import sleep
    from selenium import webdriver
    from ddt import ddt,data,file_data,unpack
     
    @ddt
    class TestBaidu(unittest.TestCase):
        @classmethod
        def setUpClass(cls):
            cls.driver=webdriver.Chrome()
            cls.driver.get("http://www.baidu.com")
            cls.driver.maximize_window
     
        @classmethod
        def tearDownClass(cls):
            cls.driver.quit()
     
        def search(self,search_key):
            self.driver.find_element_by_id("kw").clear()
            self.driver.find_element_by_id("kw").send_keys(search_key)
            self.driver.find_element_by_id("su").click()
            sleep(5)
     
        @data(
                ("case1","selenium"),
                ("case2","python")
        )
        @unpack
        def test_search1(self,name,search_key):
            print("第一组测试用例:",name)
            self.search(search_key)
            self.assertEqual(self.driver.title,search_key+"_百度搜索")
     
        @data(
                ["case1","selenium"],
                ["case2","python"]
        )
        @unpack
        def test_search2(self,name,search_key):
            print("第二组测试用例:",name)
            self.search(search_key)
            self.assertEqual(self.driver.title,search_key+"_百度搜索")
     
        @data(
                {"key":"selenium"},
                {"key":"python"}
        )
        @unpack
        def test_search3(self,key):
            print("第三组测试用例:",key)
            self.search(key)
            self.assertEqual(self.driver.title,key+"_百度搜索")
     
    if __name__ == '__main__':  
        unittest.main(verbosity=2)  

执行报错如下时,是因为文件名也为ddt:

PS E:\selenium> & "D:/Program Files/Python39/python.exe" e:/selenium/Test/unittest/ddt.py
    Traceback (most recent call last):
      File "e:\selenium\Test\unittest\ddt.py", line 4, in <module>
        from ddt import ddt,data,file_data,unpack
      File "e:\selenium\Test\unittest\ddt.py", line 4, in <module>
        from ddt import ddt,data,file_data,unpack
   
 ImportError: cannot import name 'ddt' from partially initialized module
 'ddt' (most likely due to a circular import) 
(e:\selenium\Test\unittest\ddt.py)    

10 数据文件的参数化

@file_data()装饰器中内容为文件名称。支持json格式和yaml格式。

import unittest
    from time import sleep
    from selenium import webdriver
    from ddt import ddt,data,file_data,unpack
     
    @ddt
    class TestBaidu(unittest.TestCase):
        @classmethod
        def setUpClass(cls):
            cls.driver=webdriver.Chrome()
            cls.driver.get("http://www.baidu.com")
            cls.driver.maximize_window
     
        @classmethod
        def tearDownClass(cls):
            cls.driver.quit()
     
        def search(self,search_key):
            self.driver.find_element_by_id("kw").clear()
            self.driver.find_element_by_id("kw").send_keys(search_key)
            self.driver.find_element_by_id("su").click()
            sleep(5)
     
        @file_data('ddt_data.json')
        @unpack
        def test_search1(self,search_key):
            print("第一组测试用例:",search_key)
            self.search(search_key)
            self.assertEqual(self.driver.title,search_key+"_百度搜索")
     
        @file_data('ddt_data_yml.yaml')
        @unpack
        def test_search2(self,case):
            search_key=case[0]["search_key"]
            print("第二组测试用例:",search_key)
            self.search(search_key)
            self.assertEqual(self.driver.title,search_key+"_百度搜索")
    if __name__ == '__main__':  
        unittest.main(verbosity=2)  
ddt_data.json
    {
        "case1": {"search_key": "python"},
        "case2": {"search_key": "ddt"}
    }
ddt_data_yml.yaml
    case1:
     - search_key: "python"
    case2:
     - search_key: "ddt"

技术行业要不断地学习,学习肯定不要孤军奋战,最好是能抱团取暖,相互成就一起成长,群众效应的效果是非常强大的,大家一起学习,一起打卡,会更有学习动力,也更能坚持下去。你可以加入我们的测试技术交流扣扣群:914172719(里面有各种软件测试资源和技术讨论)

送给大家一句话,共勉:当我们能力不足的时候,首先要做的是内修!当我们能力足够强大的时候,就可以外寻了!

最后也为大家准备了一份配套的学习资源,你能在 公众号:【伤心的辣条】免费获取一份216页软件测试工程师面试宝典文档资料。以及相对应的视频学习教程免费分享!,其中资料包括了有基础知识、Linux必备、Shell、互联网程序原理、Mysql数据库、抓包工具专题、接口测试工具、测试进阶-Python编程、Web自动化测试、APP自动化测试、接口自动化测试、测试高级持续集成、测试架构开发测试框架、性能测试、安全测试等。


好文推荐

转行面试,跳槽面试,软件测试人员都必须知道的这几种面试技巧!

面试经:一线城市搬砖!又面软件测试岗,5000就知足了…

面试官:工作三年,还来面初级测试?恐怕你的软件测试工程师的头衔要加双引号…

什么样的人适合从事软件测试工作?

那个准点下班的人,比我先升职了…

测试岗反复跳槽,跳着跳着就跳没了…

包装成1年工作经验的测试工程师,我给他的面试前的建议如下

“入职一年,那个被高薪挖来的自动化软件测试被劝退了。”

4个月自学软件测试面进阿里!如何从功能测试转成自动化…我经历了什么

6000元报了培训班,3个月后我成功“骗”进了腾讯大厂,月薪15000

在这里插入图片描述

标签:__,search,driver,unittest,单元测试,key,搞懂,self
来源: https://blog.csdn.net/AI_Green/article/details/122084077

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有