文档章节

UnitTest测试框架应用

爱码小士
 爱码小士
发布于 2019/12/17 14:15
字数 3781
阅读 68
收藏 0

一.UnitTest在自动化测试中的应用

UnitTest是Python语言的单元测试框架,UnitTest单元测试框架提供了创建测试用例,测试套件,和批量执行测试用例的方法。

在Python安装成功后,UnitTest单元测试框架可以直接导入使用,他属于Python的标准库;作为单元测试的框架,UnitTest单元测试框架也是对程序的最小模块进行的一种敏捷化的测试。在自动化测试中,我们虽然不需要做白盒测试,但是必须知道所使用语言的单元测试框架,这是因为后面我们测试,就会遇到用例组织的问题,虽然函数式编程和面向对象编程提供了对代码的重构,但是对于所编写的每个测试用例,不可能编写成一个函数来调用执行;利用单元测试框架,可以创建一个类,该类继承unittest的TestCase,这样可以把每个TestCase看成是一个最小的单元,由测试套件组织起来,运行时直接执行即可,同时可引入测试报告。

1# TestCase
2# 类,必须要继承unittest.TestCase
3# 一个类class继承 unittest.TestCase,就是一个测试用例。一个TestCase的实例就是一个测试用例,就是一个完整的测试流程。
4# 包括测试前环境准备setUp()|setUpClass()、执行代码run()、测试环境后的还原tearDown()|tearDownClass()。
5# 继承自unittest.TestCase的类中,测试方法的名称要以test开头。且只会执行以test开头定义的方法(测试用例)。

二、测试固件(TestFixture)

在unittest单元测试框架中,测试固件用于处理初始化的操作,例如,在对百度的搜索进行测试前,首先需要打开浏览器并且进入百度的首页;测试结束后,需要关闭浏览器;测试固件提哦功能了两种执行形式,一种是每执行一个测试用例,测试固件就会被执行一次;另外一种就不管有多少个用例,测试固件只会执行一次

1# 用于一个测试环境的准备和销毁还原。
2# 当测试用例每次执行之前需要准备测试环境,每次测试完成后还原测试环境,比如执行前连接数据库、打开浏览器等,执行完成后需要还原数据库、关闭浏览器等操作。
3# 这时候就可以启用testfixture。
4
5# setUp():准备环境,执行每个测试用例的前置条件;
6# tearDown():环境还原,执行每个测试用例的后置条件;
7# setUpClass():必须使用@classmethod装饰器,所有case执行的前置条件,只运行一次;
8# tearDownClass():必须使用@classmethod装饰器,所有case运行完后只运行一次;

 

1、测试固件每次均执行

unittest单元测试框架提供了名为setUp的tearDown的测试固件。下面,我们通过编写一个例子来看测试固件的执行方式,测试代码如下

 1  import unittest
 2
 3  class Test1(unittest.TestCase):
 4
 5      # 测试固件之前置条件
 6      def setUp(self):
 7          print("这是前置条件")
 8
 9      # 测试固件之后置条件
10     def tearDown(self):
11         print("这是后置条件")
12
13     def test_case1(self):
14         print("test_case1")
15
16     def test_case2(self):
17         print("test_case2")
18
19
20 if __name__ == '__main__':
21     unittest.main(verbosity=2)

执行结果如下:

他的执行顺序是先执行setUp方法,在执行具体的用例,最后执行tearDown方法

2、测试固件只执行一次

钩子方法setUp和tearDown虽然经常使用,但是在自动化测试中,一个系统的测试用例多达上千条,每次都执行一次的setUp和tearDown方法会耗费大量的性能,在unittest单元测试框架中还可以使用另外一种测试固件来解决这一问题,他就是setUpClass和tearDownClass方法,该测试固件方法是类方法,需要在方法上面加装饰器@classmethod,使用该测试固件,不管有多少个用例,测试固件只执行一次,具体代码如下

 1 import unittest
 2 
 3 class Test1(unittest.TestCase):
 4     # def setUp(self):
 5     #     print("这是前置条件")
 6     #
 7     # def tearDown(self):
 8     #     print("这是后置条件")
 9     
10     @classmethod
11     def setUpClass(cls):
12         print("这是类方法前置条件")
13 
14     @classmethod
15     def tearDownClass(cls):
16         print("这是类方法后置条件")
17 
18     def test_case1(self):
19         print("test_case1")
20 
21     def test_case2(self):
22         print("test_case2")
23 
24 
25 if __name__ == '__main__':
26     unittest.main(verbosity=2)

 结果如下:

3、两种测试固件并存

 1 import unittest
 2
 3
 4class Test1(unittest.TestCase):
 5    def setUp(self):
 6        print("这是前置条件")
 7
 8    def tearDown(self):
 9        print("这是后置条件")
10
11    @classmethod
12    def setUpClass(cls):
13        print("这是类方法前置条件")
14
15    @classmethod
16    def tearDownClass(cls):
17        print("这是类方法后置条件")
18
19    def test_case1(self):
20        print("test_case1")
21
22    def test_case2(self):
23        print("test_case2")
24
25
26if __name__ == '__main__':
27    unittest.main(verbosity=2)

执行结果如下:

三、测试执行

在以上事例中,可以看到测试用例的执行是在主函数中,unittest调用的是main,代码如下,TestProjram还是一个类,再来看该类的构造函数,代码如下

  main = TestProgram

TestProjram还是一个类,再来看该类的构造函数,代码如下

 1class TestProgram(object):
 2    """A command-line program that runs a set of tests; this is primarily
 3       for making test modules conveniently executable.
 4    """
 5    # defaults for testing
 6    module=None
 7    verbosity = 1
 8    failfast = catchbreak = buffer = progName = warnings = None
 9    _discovery_parser = None
10
11    def __init__(self, module='__main__', defaultTest=None, argv=None,
12                    testRunner=None, testLoader=loader.defaultTestLoader,
13                    exit=True, verbosity=1, failfast=None, catchbreak=None,
14                    buffer=None, warnings=None, *, tb_locals=False):
15        if isinstance(module, str):
16            self.module = __import__(module)
17            for part in module.split('.')[1:]:
18                self.module = getattr(self.module, part)
19        else:
20            self.module = module
21        if argv is None:
22            argv = sys.argv
23
24        self.exit = exit
25        self.failfast = failfast
26        self.catchbreak = catchbreak
27        self.verbosity = verbosity
28        self.buffer = buffer
29        self.tb_locals = tb_locals
30        if warnings is None and not sys.warnoptions:
31            # even if DeprecationWarnings are ignored by default
32            # print them anyway unless other warnings settings are
33            # specified by the warnings arg or the -W python flag
34            self.warnings = 'default'
35        else:
36            # here self.warnings is set either to the value passed
37            # to the warnings args or to None.
38            # If the user didn't pass a value self.warnings will
39            # be None. This means that the behavior is unchanged
40            # and depends on the values passed to -W.
41            self.warnings = warnings
42        self.defaultTest = defaultTest
43        self.testRunner = testRunner
44        self.testLoader = testLoader
45        self.progName = os.path.basename(argv[0])
46        self.parseArgs(argv)
47        self.runTests()

 在unittest模块中包含的main方法,可以方便的将测试模块转变为可以运行的测试脚本。main使用unittest.TestLoader类来自动查找和加载模块内的测试用例,TestProgram类中的该部分的代码如下

 def createTests(self):
        if self.testNames is None:
            self.test = self.testLoader.loadTestsFromModule(self.module)
        else:
            self.test = self.testLoader.loadTestsFromNames(self.testNames,
                                                           self.module)

在执行测试用例时候,在main方法中加入了verbosity=2,代码如下

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

 下面解释一下verbosity部分,在verbosity中默认是1。0代表执行的测试总数和全局结果,2代表详细的信息

四、测试套件,TestSuite

# TestSuite
# 上述简单的测试会产生两个问题,可不可以控制test测试用例的执行顺序?若不想执行某个测试用例,有没有办法可以跳过?
# 对于执行顺序,默认按照test的 A-Z、a-z的方法执行。若要按自己编写的用例的先后关系执行,需要用到testSuite。
# 把多个测试用例集合起来,一起执行,就是testSuite。testsuite还可以包含testsuite。
# 一般通过addTest()或者addTests()向suite中添加。case的执行顺序与添加到Suite中的顺序是一致的。

1、直接执行案例

我们在func.py这个文件中定义加减乘除4个测试函数

#Auther Bob
#--*--conding:utf-8 --*--
def add(a,b):
    return a + b
def minus(a,b):
    return a - b
def multi(a,b):
    return a * b
def divide(a,b):
    return a / b

然后在myunittest.py文件中定义我们的测试代码,这里用到了断言,我们后面会介绍

from test1 import func

class Test2(unittest.TestCase):
    def setUp(self):
        print("前置条件")

    def tearDown(self):
        print("后置条件")

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

    def test_minus(self):
        self.assertEqual(4,func.minus(5,1))

    def test_multi(self):
        self.assertEqual(4,func.multi(2,2))

    def test_divide(self):
        self.assertEqual(10,func.divide(100,10))


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

执行结果如下:

2、添加案例到测试套件中

上述简单的测试会产生两个问题,可不可以控制test测试用例的执行顺序?若不想执行某个测试用例,有没有办法可以跳过?

对于执行顺序,默认按照test的 A-Z、a-z的方法执行。若要按自己编写的用例的先后关系执行,需要用到testSuite。

把多个测试用例集合起来,一起执行,就是testSuite。testsuite还可以包含testsuite。

一般通过addTest()或者addTests()向suite中添加。case的执行顺序与添加到Suite中的顺序是一致的。

如果用到测试套件TestSuite,则需要先写好测试代码,但是先不要执行

我们同样在myunittest.py文件中定义我们的测试代码

from test1 import func


class Test3(unittest.TestCase):
    def setUp(self):
        print("前置条件")

    def tearDown(self):
        print("后置条件")


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


    def test_minus(self):
        self.assertEqual(4,func.minus(5,1))


    def test_multi(self):
        self.assertEqual(4,func.multi(2,2))

    def test_divide(self):
        self.assertEqual(10,func.divide(100,10))

 我们在test_suit.py文件中引入测试案例,然后通过TestSuite类的addTests方法把测试用例添加到测试套件中

import unittest
from test1.myunittest import Test3
# from test1.myunittest2 import Test3 as t3



if __name__ == '__main__':
    # 输出信息到控制台

    # 实例化一个TestSuite类
    suite = unittest.TestSuite()

    # 把需要执行的案例放在一个list中
    tests = [Test3("test_add"), Test3("test_minus"), Test3("test_multi"), Test3("test_divide")]

    # 把案例添加到实例化好的测试套件中
    suite.addTests(tests)
    # t = [t3("test_add"), t3("test_minus"), t3("test_multi"), t3("test_divide")]
    # suite.addTests(tests)

    # 实例化一个参数执行类
    runner = unittest.TextTestRunner(verbosity=2)

    # 测试执行类的实例执行测试套件
    runner.run(suite)

以上的案例我们是添加一个文件的测试案例,我们同样可以添加多个文件中的案例到一个测试套件中,然后执行这个测试套件即可

import unittest
from test1.myunittest import Test3
from test1.myunittest2 import Test3 as t3



if __name__ == '__main__':
    # 输出信息到控制台

    # 实例化一个TestSuite类
    suite = unittest.TestSuite()

    # 把需要执行的案例放在一个list中
    tests = [Test3("test_add"), Test3("test_minus"), Test3("test_multi"), Test3("test_divide")]

    # 把案例添加到实例化好的测试套件中
    suite.addTests(tests)

    # 添加另外一个文件中的测试案例到测试套件中
    t = [t3("test_add"), t3("test_minus"), t3("test_multi"), t3("test_divide")]
    suite.addTests(t)

    # 实例化一个参数执行类
    runner = unittest.TextTestRunner(verbosity=2)

    # 测试执行类的实例执行测试套件
    runner.run(suite)

 上面的执行方式是输出结果到控制台,我们也可以输出结果到文件中

import unittest
from test1.myunittest import Test3
from test1.myunittest2 import Test3 as t3



if __name__ == '__main__':

    # 输出信息到txt文件中
    suite = unittest.TestSuite()
    tests = [Test3("test_add"), Test3("test_minus"), Test3("test_multi"), Test3("test_divide")]
    suite.addTests(tests)
    t = [t3("test_add"), t3("test_minus"), t3("test_multi"), t3("test_divide")]
    suite.addTests(t)
    with open('UnittestTextReport.txt', 'a') as  f:
        runner = unittest.TextTestRunner(stream=f, verbosity=2)
        runner.run(suite)

3、直接添加测试类到测试套件中

案例一个一个添加还是比较麻烦,我们可以直接添加一个测试类到测试套件中

利用下面的方法加载一个测试类

unittest.TestLoader().loadTestsFromTestCase(t3)

 

import unittest
from unittest import TestLoader

from test1 import myunittest

from test1.myunittest2 import Test3 as t3

if __name__ == '__main__':
    suite = unittest.TestSuite()
    loader = TestLoader()
    test_cases1 = unittest.TestLoader().loadTestsFromTestCase(t3)
    # 参数是一个类,而这个类必须是unittest.TestCase的子类或者孙类
    suite.addTests(test_cases1)
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(suite)

4、直接加载一个模块到测试套件中,如果这个模块中有多个类,则会把所有的类的测试案例加载到测试套件中

unittest.TestLoader().loadTestsFromModule(myunittest)

 

import unittest
from unittest import TestLoader

from test1 import myunittest

from test1.myunittest2 import Test3 as t3

if __name__ == '__main__':
    suite = unittest.TestSuite()
    loader = TestLoader()
    test_cases1 = unittest.TestLoader().loadTestsFromModule(myunittest)
    # 参数是一个模块,会把这个模块里的所有case加载进来
    suite.addTests(test_cases1)
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(suite)

截图如下

5、通过案例名称添加案例到测试套件中

 test_cases1 = unittest.TestLoader().loadTestsFromName('test1.myunittest2.Test3.test_minus')

 

 import unittest
from unittest import TestLoader

from test1 import myunittest

from test1.myunittest2 import Test3 as t3

if __name__ == '__main__':

    suite = unittest.TestSuite()
    loader = TestLoader()
    test_cases1 = unittest.TestLoader().loadTestsFromName('test1.myunittest2.Test3.test_minus')
    # 加载某个cese
    runner = unittest.TextTestRunner(verbosity=2)
    suite.addTests(test_cases1)
    runner.run(suite)

截图如下

五、忽略执行案例

 

在实际的项目中,有些案例我们可能暂时不需要执行,如果有这样的问题,我们该怎么办,unittest框架已经为我们提供了解决方案

1、无条件跳过该案例,用该装饰器修饰要执行的案例,则该案例会被忽略不执行

@unittest.skip("do not exec")

 

 @unittest.skip("do not exec")
    # 无条件跳过执行该案例
    def test_add(self):
        self.assertEqual(3,func.add(1,2))

2、满足某个条件才跳过该案例 

  @unittest.skipIf(4 > 3,"2 > 3 do not exec")
 @unittest.skipIf(4 > 3,"2 > 3 do not exec")
    # 满足某个条件才跳过执行
    def test_minus(self):
        self.assertEqual(4,func.minus(5,1))

 3、不满足某个条件才跳过案例

 @unittest.skipUnless(4 < 3,"hahah")
   @unittest.skipUnless(4 < 3,"hahah")
    # 不满足某个条件才跳过执行
    def test_multi(self):
        self.assertEqual(4,func.multi(2,2))

 4、我们也可以在案例里面定义忽略执行这条案例

    def test_divide(self):
        self.skipTest("wydd")
        self.assertEqual(10,func.divide(100,10))

六、断言

断言就是判断实际测试结果与预期结果是否一致,一致则测试通过,否则失败。

因此,在自动化测试中,无断言的测试用例是无效的,这是因为当一个功能自动化已经全部实现,在每次版本迭代中执行测试用例时,执行的结果必须是权威的,也就是说自动化测试用例执行结果应该无功能性或者逻辑性问题,在自动化测试中最忌讳的就是自动化测试的用例虽然是通过的,但是被测试的功能却是存在问题的,自动化测试用例经常应用在回归测试中,发现的问题不是特别多,如果测试结果存在功能上的问题,则投入了人力去做的自动化参数就没有多大的意义了,所以每一个测试用例必须要有断言;

在测试的结果中只有两种可能,一种是执行通过,另外一种是执行失败,也就是功能存在问题,在TestCase类中提供了assert方法来检查和报告失败,常用的方法如下

    self.assertEqual(3,func.add(1,2))
        # 判断是否相等

        self.assertNotEqual()
        # 判断是否不等于

        self.assertTrue()
        # 判断布尔值是否为True

        self.assertFalse()
        # 判断布尔值是否为False

        self.assertIs()
        # 判断类型是否相同

        self.assertIsNot()
        # 判断类型是否不同

        self.assertIsNone()
        # 判断是否为None

        self.assertIsNotNone()
        # 判断是否不为None

        self.assertIn()
        # 判断在某个范围内

        self.assertNotIn()
        # 判断是否不在某个范围内

        self.assertIsInstance()
        # 判断是否为某个类的实例

        self.assertNotIsInstance()

 

 

 

              扫码关注,更多精彩

© 著作权归作者所有

爱码小士
粉丝 56
博文 83
码字总数 194222
作品 0
深圳
技术主管
私信 提问
加载中

评论(0)

python接口自动化(二十一)--unittest简介(详解)

简介   前边的随笔主要介绍的requests模块的有关知识个内容,接下来看一下python的单元测试框架unittest。熟悉 或者了解java 的小伙伴应该都清楚常见的单元测试框架 Junit 和 TestNG,这个...

SEOwhywhy
2019/04/23
123
0
selenium2-python28-引入unittest单元测试框架-unittest 单元测试框

上一节大概介绍了如何通过selenium ide自动生成unittest框架的测试脚本。本节则要详细的介绍unittest是如何帮助我们完成单元测试的。 unittest框架又名PyUnti框架为python语言的单元测试框架...

丰_申
2016/03/11
13
0
Selenium Webdriver 学习(1)--install

step 1 首先当然是安装,这边先要安装python www.python.org/download里面有两个版本可以选,一个是python3, 一个是python2,由于之前一直在用2,所以仍然选择2.7.11 step 2 安装setup-too...

terry_hding
2016/01/07
116
0
Python单元测试:unittest使用简介

一、概述 本文介绍python的单元测试框架unittest,这是Python自带的标准模块unittest。unittest是基于java中的流行单元测试框架junit设计的,其功能强大且灵活,对于熟悉junit的人来说掌握u...

51kata
2016/09/20
0
0
黑盒测试在App自动化测试中的应用

不废话,直接来。 先说说什么是黑盒测试 黑盒测试,这里就说的是app功能测试,之前看到一个介绍说,就是在测试中,把测试对象看作一个黑盒子。利用黑盒测试法进行动态测试时,需要测试应用产...

aabbc
2016/11/02
225
0

没有更多内容

加载失败,请刷新页面

加载更多

【 开发指南 】智能家居技能

本文作者:DuerOs 目录 一、教学视频 二、整体架构 三、开发步骤&资料整理 四、常见问题解答 五、智能家居文档 树状提纲 ————————————————————————————————...

百度开发者中心
2019/03/29
23
0
008. 并发容器类 Map

1. JDK 源码学习方法 1. 演绎推导法 示例:因果推理。 因为 JAVA 中只提供了 BIO 和 NIO 两种方式,所以一切框架中,涉及到网络处理的,都可以用这两个知识点去探究原理。 2. 归纳总结法 示例...

紫穹
今天
71
0
如何使用sed替换换行符(\\ n)? - How can I replace a newline (\n) using sed?

问题: How can I replace a newline (" \\n ") with a space (" 如何将换行符(“ \\n ”)替换为空格(“ ") using the sed command? “)使用sed命令? I unsuccessfully tried: 我尝试失......

javail
今天
109
0
OSChina 周一乱弹 —— 原来这叫分别焦虑

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @薛定谔的兄弟 :分享洛神有语创建的歌单「我喜欢的音乐」: 《A Careful Tearing》- Levi Patel 手机党少年们想听歌,请使劲儿戳(这里) 清明...

小小编辑
今天
182
0
trim、stripslashes、htmlspecialchars函数

通过 PHP 验证表单数据 我们要做的第一件事是通过 PHP 的 htmlspecialchars() 函数传递所有变量。 在我们使用 htmlspecialchars() 函数后,如果用户试图在文本字段中提交以下内容: <script>...

imzchloe
今天
130
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部