Unittest的快速入门
作者:强哥   类别:Python开发    日期:2018-12-25 10:45:45    阅读:2682 次   消耗积分:0 分

1.概述。

相信接触过Java语言的朋友一定对Junit单元测试框架不陌生,对于Python语言,同样有类似的单元测试框架Unittest。


Unittest是Python内部自带的一个单元测试的模块,它设计的灵感来源于Junit,具有和Junit类似的结构,有过Junit经验的朋友可以很快上手。Unittest具备完整的测试结构,支持自动化测试的执行,对测试用例集进行组织,并且提供了丰富的断言方法,最后生成测试报告。Unittest框架的初衷是用于单元测试,但也不限于此,在实际工作中,由于它强大的功能,提供的完整的测试流程,我们往往将其用于自动化测试的各个方面,例如在本书中大量的接口测试实例都会用到Unittest。

所谓知己知彼百战不殆,首先我们来一起看下Unittest大家庭里的成员。首先导入unittest模块,使用dir()函数获取Unittest的所有成员,并输出到界面上。


import unittest

print(dir(unittest))


执行结果如下:

['BaseTestSuite', 'FunctionTestCase', 'SkipTest', 'TestCase', 'TestLoader', 'TestProgram', 'TestResult', 'TestSuite', 'TextTestResult', 'TextTestRunner', '_TextTestResult', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__unittest', 'case', 'defaultTestLoader', 'expectedFailure', 'findTestCases', 'getTestCaseNames', 'installHandler', 'load_tests', 'loader', 'main', 'makeSuite', 'registerResult', 'removeHandler', 'removeResult', 'result', 'runner', 'signals', 'skip', 'skipIf', 'skipUnless', 'suite', 'util']


结果里显示了unittest模块的各个成员,看起来非常多,不知道如何下手。其实一个模块里往往包含了大量的成员,很大一部分我们使用的频率并不高,这时需要有重点的去攻克核心的部分,其他的稍作了解即可。


下面先简单介绍最常用的一些成员,后续的章节中我们会详细剖析。


(1) TestCase:可以说是unittest中最重要的一个类,也是测试用例类的父类,通过对其继承,使子类具备了执行测试的能力。下例中MainTest是需要执行的测试类。

Class MainTest(unittest.TestCase):


(2) TestSuite: TestSuite类用于创建测试套件。最常见的用法是,使用该类将多个测试用例添加到用例集,通过运行用例集,实现多个测试用例的执行。


(3) main:调用unittest.main()方法可以方便的将测试类里的以“test”命名开头的测试方法以脚本的形式自动执行。


(4) TextTestRunner:主要使用该类的run()方法来运行TestSuite添加好的测试用例。


(5) skipXX:装饰器。有时我们的测试只想运行其中的一部分用例,那么我们可以使用skip装饰器来跳过执行。最常见的场景是:在不同的系统环境上运行时,某些用例是不能通过的,但这并不是我们的产品或用例导致,而是环境的不兼容等问题,此时我们可以使用skip装饰器来处理。


2.重要概念。

在继续学习之前,我们需要掌握四个Unittest的重要概念。以下是官方网站上通过面向对象大的方式进行的解释。


To achieve this, unittest supports some important concepts in an object-oriented way:


test fixture

A test fixture represents the preparation needed to perform one or more tests, and any associate cleanup actions. This may involve, for example, creating temporary or proxy databases, directories, or starting a server process.


test case

A test case is the individual unit of testing. It checks for a specific response to a particular set of inputs. unittest provides a base class, TestCase, which may be used to create new test cases.


test suite

A test suite is a collection of test cases, test suites, or both. It is used to aggregate tests that should be executed together.


test runner

A test runner is a component which orchestrates the execution of tests and provides the outcome to the user. The runner may use a graphical interface, a textual interface, or return a special value to indicate the results of executing the tests.


(1) test fixture:翻译过来是测试固定装置的意思。形象的说,把整个测试过程看作大的装置,这个装置里不仅具有测试执行部件,还有测试之前环境准备和测试之后环境清理的部件,有机的结合起来就是一个更大的测试装置,即test fixture。


(2) test case:测试用例,注意与前面的TestCase类不是同一个概念。一个完整的测试流程就是一个测试用例,通过一些特定的输入得到响应,并对响应进行校验的过程。我们通过去继承TestCase这个父类,可以创建新的测试用例。


(3) test suite:测试套件,也称为测试集合。多个测试用例组合在一起就形成了测试集,当然测试集里不仅能包含测试用例,也可以再次嵌套测试集,测试集可以用于代码的组织和运行。


(4) test runner:是Unittest中的重要组成部分,主要职责为执行测试,通过图形、文本或者返回一些特殊值的方式来呈现最终的运行结果。例如执行的用例数、成功和失败的用例数。


图3-1展示了他们之间的关系,test fixture是包含了以test case为核心的整个组件,多个test case可以集合到一个test suite中,最后调用test runner执行并生成结果。

20181225_103902_871.png

(Unittest组成部分)


3.实例。

下面我们通过一个简单的实例让大家对Unittest的基本使用有一个直观的认识。首先创建一个项目,项目里有两个文件,Calculator.py是被测试的代码,Demo.py是执行测试的代码。项目结构如下:


20181225_103916_024.png


(1) 被测代码准备。在Calculator类中定义了一个方法为divide,该方法接收x和y两个参数分别作为分子和分母进行除法运算,并返回运算结果。


class Calculator:

    def divide(self,x,y):

        return x / y


(2) 测试代码。测试代码先通过from和import两种方式分别导入了Calculator和unittest模块,然后定义了一个测试类TestCalculator,并继承于unittest.TestCase模块。测试类中有一个测试方法test_divide,调用了被测试类Calculator中的divide方法,并将结果进行断言。最后调用unittest.main方法来执行当前类中所有以test开头的方法来直接运行,而不必再专门对TestCalculator进行实例化。


import unittest

from my_unittest.unittest_demo.Calculator import Calculator


class TestCalculator(unittest.TestCase):

    def testDivide01(self):

        cal = Calculator()

        result = cal.divide(10,2)

        self.assertEqual(result,5)


    def testDivide02(self):

        cal = Calculator()

        result = cal.divide(20,0.5)

        self.assertEqual(result,40)


if __name__ == '__main__':

    unittest.main()


(3)运行结果如下。两个测试总共运行了0.001秒,测试结果为OK。


..

---------------------------------------------------------------------

Ran 2 tests in 0.001s


OK


(4)接下来我们再看一个测试不通过的例子,依然使用Calculator作为待测试的类,测试类中包含3个测试方法,即3条测试用例:


from C03_Unittest.Ex01_SimpleExample.Calculator import Calculator


class TestCalculator(unittest.TestCase):

    def testDivide01(self):

        cal = Calculator()

        result = cal.divide(10,2)

        self.assertEqual(result,5)


    def testDivide02(self):

        cal = Calculator()

        result = cal.divide(10,0.5)

        self.assertEqual(result,10)


    def testDivide03(self):

        cal = Calculator()

        result = cal.divide(10,0)

        self.assertEqual(result,0)


if __name__ == '__main__':

    unittest.main()


(5) 第一个方法(即第一条测试用例)用10除以2,预期结果为5,测试结果通过;第二条测试用例用10除以0.5,为了观察运行结果,刻意设置错误的预期结果为10,但实际结果为20,出现“AssertionError: 0.01 != 0.001”,断言错误,测试失败;第三条用属于异常测试,使用10除以0,出现运行错误“ZeroDivisionError: division by zero”,提示不能使用0作为分母。结果中的第一行“.FE”分别代表运行中的三条用例,“.”为通过,“F”为不通过,“E”为错误。


.FE

=====================================================================

ERROR: testDivide03 (__main__.TestCalculator)

---------------------------------------------------------------------

Traceback (most recent call last):

  File "C:/Users/Administrator/PycharmProjects/python364/C03_Unittest/Ex01_SimpleExample/Test02.py", line 17, in testDivide03

    result = cal.divide(10,0)

  File "C:\Users\Administrator\PycharmProjects\python364\C03_Unittest\Ex01_SimpleExample\Calculator.py", line 3, in divide

    return x / y

ZeroDivisionError: division by zero


=====================================================================

FAIL: testDivide02 (__main__.TestCalculator)

---------------------------------------------------------------------

Traceback (most recent call last):

  File "C:/Users/Administrator/PycharmProjects/python364/C03_Unittest/Ex01_SimpleExample/Test02.py", line 13, in testDivide02

    self.assertEqual(result,10)

AssertionError: 20.0 != 10


---------------------------------------------------------------------

Ran 3 tests in 0.003s


FAILED (failures=1, errors=1)


(6) 通过上面的测试,可以得出一个结论:Calculator类的divide方法具有明显的Bug,该方法中没有对输入参数进行校验,导致在y为0时程序运行错误。当测试人员发现此Bug后应及时通知开发人员进行修复,避免造成更严重的损失。这个实例不仅展现了Unittest框架的实际价值,也进一步体现了测试工作在研发过程中的重要意义。







为了答谢大家对蜗牛学院的支持,蜗牛学院将会定期对大家免费发放干货,敬请关注蜗牛学院的官方微信。


20181009_153045_341.jpg




   
版权所有,转载本站文章请注明出处:蜗牛笔记, http://www.woniunote.com/article/250
上一篇: 西安校区第三期班全员就业,人均月薪6.6K
下一篇: 一文详解:软件测试技术体系中的20条专业术语
提示:登录后添加有效评论可享受积分哦!
最新文章
    最多阅读
      特别推荐
      回到顶部