davieyang

单元测试框架之unittest(六)

一、摘要

本片博文将介绍unittest框架的一些轻便有效的特性,在我们的测试中经常可以用到

  • 如果有一些测试方法不想执行,如果有些测试方法在某些条件下不执行 该当如何?
  • 如果有些方法未在unittest框架下编写,又想使用unittest框架执行,该当如何?
  • 如果想自定义一个执行顺序该当如何?

二、代码实例

如果有一些测试方法不想执行,如果有些测试方法在某些条件下不执行 该当如何?

# coding : utf-8
import unittest
import random
import sys


class TestSequenceFunctions(unittest.TestCase):
    a = 1
    b = 2

    def setUp(self):
        self.seq = list(range(10))
        self.list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13]

    @unittest.skip("就跳过了不为什么")
    def test_shuffle(self):
        random.shuffle(self.seq)
        self.seq.sort()
        self.assertEqual(self.seq, list(range(10)))
        self.assertRaises(TypeError, random.shuffle, (1, 2, 3))

    @unittest.skipIf(a != 1, "如果a不等于1就跳过此测试方法")
    def test_choic(self):
        element = random.choice(self.seq)
        self.assertTrue(element in self.seq)

    @unittest.skipUnless(b > 1, "除非b大于1,否则跳过")
    def test_sample(self):
        with self.assertRaises(ValueError):
            random.sample(self.seq, 20)
        for element in random.sample(self.seq, 5):
            self.assertTrue(element in self.seq)

    @unittest.expectedFailure
    def test_randomshuffle(self):
        random.shuffle(self.list)
        print(self.list)
        self.assertEqual(self.list, [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13])


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

执行结果会是:

Expected failure: Traceback (most recent call last):
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2018.3.1\helpers\pycharm\teamcity\diff_tools.py", line 32, in _patched_equals
    old(self, first, second, msg)
  File "C:\Python37\lib\unittest\case.py", line 839, in assertEqual
    assertion_func(first, second, msg=msg)
  File "C:\Python37\lib\unittest\case.py", line 1045, in assertListEqual
    self.assertSequenceEqual(list1, list2, msg, seq_type=list)
  File "C:\Python37\lib\unittest\case.py", line 1027, in assertSequenceEqual
    self.fail(msg)
  File "C:\Python37\lib\unittest\case.py", line 680, in fail
    raise self.failureException(msg)
AssertionError: Lists differ: [4, 1, 9, 2, 7, 8, 3, 11, 6, 5, 13] != [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13]

First differing element 0:
4
1

- [4, 1, 9, 2, 7, 8, 3, 11, 6, 5, 13]
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13]

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Python37\lib\unittest\case.py", line 59, in testPartExecutor
    yield
  File "C:\Python37\lib\unittest\case.py", line 615, in run
    testMethod()
  File "D:\Programs\Python\Demo\unittest6\SkipDemo.py", line 38, in test_randomshuffle
    self.assertEqual(self.list, [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13])
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2018.3.1\helpers\pycharm\teamcity\diff_tools.py", line 38, in _patched_equals
    raise error
teamcity.diff_tools.EqualsAssertionError:  :: [4, 1, 9, 2, 7, 8, 3, 11, 6, 5, 13] != [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13]



Ran 4 tests in 0.010s

OK (skipped=1, expected failures=1)

Skipped: 就跳过了不为什么

代码解析:

unittest为我们提供了多种跳过测试用例的方法,当我们的大量用例在不同场景下可能有些用例并不想执行,例如回归测试、例如新部署的一套环境需要对主功能进行验证、例如有些用例需要具备条件才执行等等场景我们便需要这些跳过用例的方法,当然我们可以将那些不想执行的用例注释掉,但也可以采用如下装饰器给测试方法加上注解

@unittest.skip(reason)  # 无条件跳过,reason是用来描述为什么跳过它
@unittest.skipIf(conditionreason) # 有条件跳过,当condition满足的情况下便跳过此装饰器装饰的用例
@unittest.skipUnless(conditionreason) # 有条件跳过,当condition满足的情况下便要执行此装饰器装饰的用例,与上一个相反
@unittest.expectedFailure # 用于标记期望执行失败的测试方法,如果该测试方法执行失败,则被认为成功,如果执行成功,则被认为失败
  • 并且当测试模块被装饰器装饰为跳过时,它的setUpModule()和tearDownModule()也就不会执行了
  • 同样的当测试类被装饰器装饰为跳过时,它的setUpClass()和tearDownClass()也就不会执行了
  • 一样的当测试方法被装饰器装饰为跳过时,它的setUp()和tearDown()也就不会执行了

如果想自定义一个执行顺序该当如何?

在前边的文章中介绍了多种执行用例的方式,首先unittest.main()这种方式启动单元测试去执行,各测试方法的执行顺序是按所有方法名的字符串的ASCII码排序后的顺序执行的

如果想自定义顺序执行,我们需要使用TestSuite(), 它的执行顺序是按照我们addTest()的次序进行执行的

# encoding = utf-8
import unittest
from unittest3.TestSuiteDemo2 import *


def suite():
    suite = unittest.TestSuite()
    suite.addTest(TestRandomFunction("test_randomchoice"))
    suite.addTest(TestRandomShuffleFunction("test_randomshuffle"))
    return suite


if __name__ == '__main__':
    runner = unittest.TextTestRunner()
    runner.run(suite())

如果有些方法未在unittest框架下编写,又想使用unittest框架执行,该当如何?

当我们的一些老代码并没建立在unittest的体系中,但是如果想使用unittest去执行它,又不想将所有老代码转换到unittest的时候,unittest为我们提供了unittest.FunctionTestCase(testFuncsetUp=NonetearDown=Nonedescription=None)

假设我们有个测试方法如下

    def test_randomchoice(self):
        var = random.choice(self.str)
        self.assertTrue(var in self.str)
        print(var)

它并没有建立在unittest框架中,只是一个独立的函数,那么我们可以创建等价的测试用例

testcase = unittest.FunctionTestCase(test_randomchoice, setUp=makeSomethingDB, tearDown=deleteSomethingDB)

然而并不建议使用这种方法,如果大量的这种代码出现,将使得测试代码比较混乱难以维护,和重构

发表于 2018-12-28 11:30 davieyang 阅读(...) 评论(...) 编辑 收藏
 

相关文章: