zoukankan      html  css  js  c++  java
  • 一文搞懂 unittest 单元测试框架

    前言

    unittest 是一款基于 Python 语言的单元测试框架。unittest 是 Python 开发包
    中的一个标准模块,使用的时候直接导入即可。

    官方文档:
    https://docs.python.org/2/library/unittest.html

    为啥要用框架?

    • 方便组建测试用例
    • 一键执行用例,跳过用例等
    • 并生成可视化测试报告
    • 他支持测试自动化,多个用例共享前置以及清理代码

    官网文档例子:

    import unittest
    print(help(unittest))
    
    

    语法规则:

    • 导入unittest:import unittest

    • 创建一个测试类,必须要继承unittest.TestCase类

    • 创建一个测试方法,且方法要以“test” 开头


    import unittest
    
    
    class IntegerArithmeticTestCase(unittest.TestCase):
        def testAdd(self):  # test method names begin with 'test'  # 测试用例的名称要以test开头
            self.assertEqual((1 + 2), 3)   # 断言,assertEqual 判断相等
            self.assertEqual(0 + 1, 1)
    
        def testMultiply(self):
            self.assertEqual((0 * 10), 0)
            self.assertEqual((5 * 8), 40)
    
    
    if __name__ == '__main__':
        unittest.main()
    
    """
    执行结果:
    ..
    ----------------------------------------------------------------------
    Ran 2 tests in 0.000s
    
    OK
    
    """
    

    unittest的执行结果:

    • 2 : 表示执行了两条用例

    • . 表示测试用例执行通过

    • F 表示执行失败

    • E 表示执行错误

    • S 表示运行跳过



    重要概念

    • Test Case:
      最小的测试单元,即测试方法。
      unittest提供了TestCase基类,我们创建的测试类要继承该基类,它可以用来创建新的测试用例。

    • Test Suite:
      测试用例、测试套件或两者的集合,用于组装一组要运行的测试。
      使用TestSuite类来创建测试套件。

    • Test Runner:
      Test Runner是一个组件,用于协调测试的执行并向用户提供结果。
      unittest提供了TextTestRunner类运行测试用例。

    • TestLoder:
      是用来加载 TestCase到TestSuite中,其中有几个loadTestsFrom_()方法,就是从各个地方寻找TestCase,创建他们的实例,然后add到TestSuite中,再返回一个TestSuite实例

    • TextTestResult:
      测试结果会保存到TextTestResult实例中,包括运行了多少用例,成功与失败多少等信息;

    • TestFixture:
      测试用例的初始化准备及环境还原,主要是setUp() 和 setDown()方法;


    测试用例执行顺序

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

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

    如何控制顺序?

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

    
    import unittest
    
    
    class IntegerArithmeticTestCase(unittest.TestCase):
        def testAdd(self):  # test method names begin with 'test'
            print("加法")
            self.assertEqual((1 + 2), 3)
            self.assertEqual(0 + 1, 1)
    
        def testMultiply(self):
            print("乘法")
            self.assertEqual((0 * 10), 0)
            self.assertEqual((5 * 8), 40)
    
    
    class SubtractionTestCase(unittest.TestCase):
        def testSubtraction(self):
            print("减法")
            self.assertEqual((5 - 3), 2)
    
    
    if __name__ == '__main__':
        # 创建测试套件
        suit = unittest.TestSuite()
        suit.addTest(IntegerArithmeticTestCase("testAdd"))  # 添加测试用例,添加 加法 用例到测试套件中
        suit.addTest(SubtractionTestCase("testSubtraction"))  # SubtractionTestCase 类名称,testSubtraction 用例名称
        # 创建测试运行器
        runner = unittest.TextTestRunner()
        runner.run(suit)
    
    """
    ..
    ----------------------------------------------------------------------
    Ran 2 tests in 0.000s
    
    OK
    加法
    减法
    
    """
    
    


    Setup和Teardown

    前置和后置
    使用场景:
    • 前置: 先登录、插入数据,再执行其他用例
    • 后置: 执行完用例,退出登录,清理数据等

    • setUpModule/tearDownModule
      在整个模块的开始与结束时被执行

    • setUpClass/ tearDownClass
      在测试类的开始与结束时被执行

    • setUp/tearDown
      在测试用例的开始与结束时被执行


    # coding:utf-8
    import unittest
    
    class TestCase(unittest.TestCase):
        def setUp(self):
            print('这是用例的前置处理')
    
        def tearDown(self):
            print('这是用例的后置处理')
    
        def test01(self):
            print('这是第一条用例')
    
        def test02(self):
            print('这是第二条用例')
    
        def test03(self):
            print('这是第三条用例')
    
    if __name__ == '__main__':
        unittest.main()
    
    """
    结果:
    ...
    ----------------------------------------------------------------------
    Ran 3 tests in 0.000s
    
    OK
    这是用例的前置处理
    这是第一条用例
    这是用例的后置处理
    这是用例的前置处理
    这是第二条用例
    这是用例的后置处理
    这是用例的前置处理
    这是第三条用例
    这是用例的后置处理
    
    """
    
    

    通过结果发现每执行一条用例,先执行的前置条件,然后执行用例内容,最后执行后置的条件。

    正常的使用场景应该是: 登录 - 执行操作,所有操作完成后 - 退出登录

    可以通过添加装饰器 @classmethod 进行执行一次前置和后置。

    # coding:utf-8
    import unittest
    
    class TestCase(unittest.TestCase):
        @classmethod
        def setUpClass(self):
            print('这是用例的前置 - 登录、插入测试数据等')
        @classmethod
        def tearDownClass(self):
            print('这是用例的后置 - 退出登录,清理数据等')
    
        def test01(self):
            print('这是第一条用例')
    
        def test02(self):
            print('这是第二条用例')
    
    
    if __name__ == '__main__':
        unittest.main()
    
    """
    结果:
    
    这是用例的前置 - 登录、插入测试数据等
    这是第一条用例
    这是第二条用例
    这是用例的后置 - 退出登录,清理数据等
    
    """
    
    


    跳过测试和预期失败

    有时候版本迭代后,部分功能暂时取消了,那么可以执行跳过用例的操作。

    import unittest
    
    
    class TestCase(unittest.TestCase):
    
        @unittest.skip("跳过这条用例")
        def test_skip(self):
            print('第一条用例')
    
        @unittest.skipIf(6 > 5, "当条件为真时跳过测试")
        def test_skip_if(self):
            print('第二条用例')
    
        @unittest.skipUnless(9 > 7, "当条件为假时跳过测试")
        def test_skip_unless(self):
            print('第三条用例')
    
        # 不论执行结果是什么,都将测试标记为失败
        @unittest.expectedFailure
        def test_fail(self):
            print('第四条用例')
    
    
    if __name__ == "__main__":
        unittest.main()
    
    """
    结果:
    
    Ran 4 tests in 0.007s
    
    FAILED (skipped=2, unexpected successes=1)
    """
    
    


    discover执行多个测试用例

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

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

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

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

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

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


    # -*- coding:utf-8 -*-
    import unittest
    
    
    def allCase():
        caseDir = "D:\\code\\ApiTest\\case"  # 测试用例路径
        discover = unittest.defaultTestLoader.discover(caseDir,
                                                       pattern="test*.py")
        print(discover)
        return discover
    
    
    if __name__ == '__main__':
        runner = unittest.TextTestRunner()
        runner.run(allCase())
    
    

    discover 加载到的用例是一个 list 集合,需要重新写入到一个 list 对象 testcase 里,
    这样就可以用 unittest 里面的 TextTestRunner 这里类的 run 方法去执行。

    返回 TextTestRunner()类的实例,

    调用 run 方法去执行 all_case()这个函数。



    Web 自动化测试

    import unittest
    from selenium import webdriver
    from time import sleep
    
    
    class TestBaiduCase(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(2)
    
    
        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()
    
    
  • 相关阅读:
    [笔记] 什么是欠采样?
    [笔记] Frequncy Divider
    [笔记] SDRAM读写控制
    能力去激活
    一个实用的SQL
    有用的SQL 语句(不断更新)
    javascript 与服务器端交互的一个小问题
    Javascript 验证码
    几个文本编辑器
    ASP.NET验证码(3种)
  • 原文地址:https://www.cnblogs.com/wwho/p/15723212.html
Copyright © 2011-2022 走看看