腾讯云双十一,腾讯云_python单元测试

  • 腾讯云双十一,腾讯云_python单元测试已关闭评论
  • 105 人浏览
  • A+
所属分类:首页

目次

python单位测试

本篇周全引见一下python中很经常运用的单位测试框架unitest。

1、unitest重要功能模块引见

unitest重要包含TestCase、TestSuite、TestLoader、TextTestRunner、TextTestResult这几个功能模块。

  • TestCase:一个TestCase实例就是一个测试用例,一个测试用例就是一个完全的测试流程,包含测试前环境的搭建,测试代码的实行,以及测试后环境的复原或许烧毁。元测试的实质也就在这里,一个测试用例是一个完全的测试单位,可以对某一具体问题举行检查考证。

  • TestSuite:多个测试用例鸠合在一起就是TestSuite,TestSuite也可以嵌套TestSuite。

  • TestLoader:TestLoader的作用是将Testcase加载到TestSuite中。

  • TextTestRunner:TextTestRunner是用来实行测试用例的,个中的run(test)会实行TestSuite/TestCase中的run(result)要领。

  • TextTestResult:TextTestResult用来保留测试结果,个中包含运转了若干测试用例,胜利了若干,失利了若干等信息。

全部流程为:写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运转TestSuite,运转的结果保留在TextTestResult中。

2、实例引见

起首预备几个待测的要领,写在test_func.py中。

def add(a, b):
    return a + b


def multi(a, b):
    return a * b


def lower_str(string):
    return string.lower()


def square(x):
    return x ** 2

预备好几个待测的要领以后,为这些要领写一个测试用例,写入our_testcase.py中。

import unittest
from test_func import *


class TestFunc(unittest.TestCase):
    """Test test_func.py"""

    def test_add(self):
        """Test func add"""
        self.assertEqual(3, add(1, 2))
        self.assertNotEqual(3, add(1, 3))

    def test_multi(self):
        """Test func multi"""
        self.assertEqual(6, multi(2, 3))
        self.assertNotEqual(8, multi(3, 3))

    def test_lower_str(self):
        """Test func lower_str"""
        self.assertEqual("abc", lower_str("ABC"))
        self.assertNotEqual("Dce", lower_str("DCE"))

    def test_square(self):
        """Test func square"""
        self.assertEqual(17, square(4))  # 这里有意设想一个会失足的用例,测试4的平方即是17,实际上并不即是。
        self.assertNotEqual(35, square(6))


if __name__ == '__main__':
    unittest.main()

这里写好以后,进入命令行终端,实行python our_testcase.py,实行结果以下。

...F
======================================================================
FAIL: test_square (__main__.TestFunc)
Test func square
----------------------------------------------------------------------
Traceback (most recent call last):
  File "our_testcase.py", line 27, in test_square
    self.assertEqual(17, square(4))
AssertionError: 17 != 16

----------------------------------------------------------------------
Ran 4 tests in 0.000s

FAILED (failures=1)

这里剖析一下这个实行结果。起首可以看到一共运转了4个测试用例,失利了1个,而且给出了失利缘由,AssertionError: 17 != 16,这是我们有意留下的毛病破绽,被测试用例测试出来了。

第一行...F中,一个点.代表测试胜利,F代表失利,我们的测试结果中,前三个胜利了,第四个失利了,统共是四个测试,其他的标记中E代表失足,S代表跳过。

迥殊申明的一点是,测试的实行递次跟要领的递次没有关系,四个测试是随机前后实行的。

每一个测试要领编写的时刻,都要以test开头,比方test_square,否则是不被unitest辨认的。

在unitest.main()中加上verbosity参数可以掌握输出的毛病报告的细致顺序,默许是1,假如设为0,则不输出每一用例的实行结果,即上面的第一行的实行结果内容。假如设为2,则输出细致的实行结果。

修正our_testcase.py中主函数。

if __name__ == '__main__':
    unittest.main(verbosity=2)

实行结果以下。

test_add (__main__.TestFunc)
Test func add ... ok
test_lower_str (__main__.TestFunc)
Test func lower_str ... ok
test_multi (__main__.TestFunc)
Test func multi ... ok
test_square (__main__.TestFunc)
Test func square ... FAIL

======================================================================
FAIL: test_square (__main__.TestFunc)
Test func square
----------------------------------------------------------------------
Traceback (most recent call last):
  File "our_testcase.py", line 27, in test_square
    self.assertEqual(17, square(4))
AssertionError: 17 != 16

----------------------------------------------------------------------
Ran 4 tests in 0.000s

FAILED (failures=1)

可以看到,每一个用例的细致实行情况以及用例名,用例形貌均被输出了出来,在测试要领下加代码示例中的"""Doc String""",在用例实行时,会将该字符串作为此用例的形貌,加适宜的解释可以使输出的测试报告越发便于浏览。

3、构造TestSuite

根据上面的测试要领,我们没法掌握用例实行的递次,如许显然是不合理的,由于在一些测试过程当中,我们一定须要掌握先测试某些用例,再测试某些用例,这些用例有前后的因果关系。在这里,我们就须要用到TestSuite。我们增加到TestSuite中的case是会根据增加的递次实行的。

另有一个问题是,我们如今只要一个测试文件,我们直接实行该文件即可,但假如有多个测试文件,怎样举行构造,总不能一个个文件实行吧,答案也在TestSuite中。

新建一个文件,test_suite.py。

import unittest
from our_testcase import TestFunc

if __name__ == '__main__':
    suite = unittest.TestSuite()
    tests = [TestFunc("test_square"), TestFunc("test_lower_str"), TestFunc("test_multi")]
    suite.addTests(tests)
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(suite)

实行结果以下。

test_square (our_testcase.TestFunc)
Test func square ... FAIL
test_lower_str (our_testcase.TestFunc)
Test func lower_str ... ok
test_multi (our_testcase.TestFunc)
Test func multi ... ok

======================================================================
FAIL: test_square (our_testcase.TestFunc)
Test func square
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/luyuze/projects/test/our_testcase.py", line 27, in test_square
    self.assertEqual(17, square(4))
AssertionError: 17 != 16

----------------------------------------------------------------------
Ran 3 tests in 0.000s

FAILED (failures=1)

如许,用例实行的递次就是根据我们增加进去的递次来实行的了。

上面运用的是TestSuite的addTests()要领,并直接传入TestCase列表,也有一些其他的要领可以向TestSuite中增加用例。

# 直接用addTest要领增加单个TestCase
suite.addTest(TestMathFunc("test_multi"))


# 运用loadTestFromName,传入模块名.TestCase名,下面俩要领结果雷同
suite.addTests(unittest.TestLoader().loadTestsFromName('our_testcase.TestFunc'))
suite.addTests(unittest.TestLoader().loadTestsFromNames(['our_testcase.TestFunc']))


# loadTestsFromTestCase(),传入TestCase
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestFunc))

用TestLoader的要领是没法对case举行排序的,同时,suite中也可以套suite。

4、输出文件

用例构造好了,然则结果只能输出到掌握台,如许没办法检察之前的实行纪录,我们想将结果输出到文件。

修正test_suite.py。

import unittest
from our_testcase import TestFunc

if __name__ == '__main__':
    suite = unittest.TestSuite()
    tests = [TestFunc("test_square"), TestFunc("test_lower_str"), TestFunc("test_multi")]
    suite.addTests(tests)

    with open('UnitestTextReport.txt', 'a') as f:
        runner = unittest.TextTestRunner(stream=f, verbosity=2)
        runner.run(suite)

5、测试前后的处置惩罚

在之前的测试中,可能会存在如许的问题:假如要在测试之前预备环境,测试完成以后做一些清算怎样办?这里须要用到的是setUp()和tearDown()。

修正our_testcase.py。

import unittest
from test_func import *


class TestFunc(unittest.TestCase):
    """Test test_func.py"""
    
    def setUp(self):
        print("do something before testcase")

    def test_add(self):
        """Test func add"""
        self.assertEqual(3, add(1, 2))
        self.assertNotEqual(3, add(1, 3))

    def test_multi(self):
        """Test func multi"""
        self.assertEqual(6, multi(2, 3))
        self.assertNotEqual(8, multi(3, 3))

    def test_lower_str(self):
        """Test func lower_str"""
        self.assertEqual("abc", lower_str("ABC"))
        self.assertNotEqual("Dce", lower_str("DCE"))

    def test_square(self):
        """Test func square"""
        self.assertEqual(17, square(4))
        self.assertNotEqual(35, square(6))
        
    def tearDownClass(self):
        print("do something after testcase")


if __name__ == '__main__':
    unittest.main(verbosity=2)

实行结果:

test_add (__main__.TestFunc)
Test func add ... do something before testcase
do something after testcase
ok
test_lower_str (__main__.TestFunc)
Test func lower_str ... do something before testcase
do something after testcase
ok
test_multi (__main__.TestFunc)
Test func multi ... do something before testcase
do something after testcase
ok
test_square (__main__.TestFunc)
Test func square ... do something before testcase
do something after testcase
FAIL

======================================================================
FAIL: test_square (__main__.TestFunc)
Test func square
----------------------------------------------------------------------
Traceback (most recent call last):
  File "our_testcase.py", line 30, in test_square
    self.assertEqual(17, square(4))
AssertionError: 17 != 16

----------------------------------------------------------------------
Ran 4 tests in 0.001s

FAILED (failures=1)

可以发明setUp()和tearDown()在每一个case前后都实行了一次。假如要在一切case实行之前和一切case实行以后预备和清算环境,我们可以运用setUpClass() 与 tearDownClass()。

class TestFunc(unittest.TestCase):
    """Test test_func.py"""

    @classmethod
    def setUpClass(cls):
        print "This setUpClass() method only called once."

    @classmethod
    def tearDownClass(cls):
        print "This tearDownClass() method only called once too."

6、跳过case

假如我们暂时想要跳过某个case不实行,unitest也有响应的要领。

  • 1、skip装潢器
# -*- coding: utf-8 -*-

import unittest
from test_func import *


class TestFunc(unittest.TestCase):
    """Test test_func.py"""

    @unittest.skip('do not run this case')
    def test_add(self):
        """Test func add"""
        self.assertEqual(3, add(1, 2))
        self.assertNotEqual(3, add(1, 3))

    def test_multi(self):
        """Test func multi"""
        self.assertEqual(6, multi(2, 3))
        self.assertNotEqual(8, multi(3, 3))

    def test_lower_str(self):
        """Test func lower_str"""
        self.assertEqual("abc", lower_str("ABC"))
        self.assertNotEqual("Dce", lower_str("DCE"))

    def test_square(self):
        """Test func square"""
        self.assertEqual(17, square(4))
        self.assertNotEqual(35, square(6))


if __name__ == '__main__':
    unittest.main(verbosity=2)

实行结果:

test_add (__main__.TestFunc)
Test func add ... skipped 'do not run this case'
test_lower_str (__main__.TestFunc)
Test func lower_str ... ok
test_multi (__main__.TestFunc)
Test func multi ... ok
test_square (__main__.TestFunc)
Test func square ... FAIL

======================================================================
FAIL: test_square (__main__.TestFunc)
Test func square
----------------------------------------------------------------------
Traceback (most recent call last):
  File "our_testcase.py", line 28, in test_square
    self.assertEqual(17, square(4))
AssertionError: 17 != 16

----------------------------------------------------------------------
Ran 4 tests in 0.000s

FAILED (failures=1, skipped=1)

结果显现为,统共实行4个测试,1个失利,1个被跳过。

skip装潢器一共有三个 unittest.skip(reason)、unittest.skipIf(condition, reason)、unittest.skipUnless(condition, reason),skip无条件跳过,skipIf当condition为True时跳过,skipUnless当condition为False时跳过。

  • 2、TestCase.skipTest()要领
class TestFunc(unittest.TestCase):
    """Test test_func.py"""

    def test_add(self):
        """Test func add"""
        self.skipTest("do not run this case")
        self.assertEqual(3, add(1, 2))
        self.assertNotEqual(3, add(1, 3))

结果与第一种是一样的。

腾讯云双十一活动