Python入门 - 第11章 测试代码(unittest简介)

此系列文章的创作初衷是作为读书过程中的笔记,而非教程类文章。

第11章 测试代码

11.1 测试函数

  • Python标准库中的unittest模块提供了代码测试工具。单元测试用于测试函数在某个方面的行为;测试用例是一组单元测试,测试了函数在各种情形下的行为是否都符合要求。全覆盖测试用例包含一整套单元测试,涵盖了函数可能遇到的各种情形。通常,最初只要对函数的重要行为编写测试代码,等到项目被广泛使用时再考虑全覆盖测试。
  • 下面的函数接受姓和名,或接受姓、名和中间名,并返回格式化的形式,这是一会要测试的函数。
def formatName(firstName: str, lastName: str, middleName: str = "") -> str:
    if middleName == "":
        return firstName.title() + " " + lastName.title()
    else:
        return firstName.title() + " " + middleName.title() + " " + lastName.title()

为了测试该函数,新建一个名为TestName.py的文件,在其中导入unittest和需要测试的函数,然后编制测试代码如下:

import unittest
from main import formatName


class NameTestCase(unittest.TestCase):
    def test_FirstLastName(self):
        str = formatName("jane", "eyre")
        self.assertEqual("Jane Eyre", str)

    def test_FirstMiddleLastName(self):
        str = formatName("wolfgang", "mozart", "amadeus")
        self.assertEqual("Wolfgang Amadeus Mozart", str)


unittest.main()

  1. 类NameTestCase是为函数formatName()编写的测试用例,它必须继承unittest.TestCase类。测试用例类的命名是任意的,但建议包含“TestCase”以指明这是一个测试用例。
  2. 类NameTestCase中含有若干单元测试,它们都以“test”开头,这样的函数在运行TestName.py文件时将被自动执行。在测试用例中编写的函数应该具有描述性的函数名(即使这样可能让函数名很长),以明确函数测试了被测试函数的哪种行为。函数中用到了断言方法来核实得到的结果是否与期望的结果一致。
  3. 在文件的最后,不要忘记调用unittest.main()来启动测试。运行上面的单元测试,将在控制台得到下面的输出。这里的两个点表明通过了两个单元测试,末尾的OK代表通过了所有的单元测试。
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
  1. 现在修改测试用例,故意让其认为函数出现了错误。输出中的“.F”表明第一个测试通过,第二个测试未通过;之后,Python输出了错误信息;并在最后告诉我们没有通过所有的单元测试,以及有几个单元测试未通过。
class NameTestCase(unittest.TestCase):
    def test_FirstLastName(self):
        str = formatName("jane", "eyre")
        self.assertEqual("Jane Eyre", str)

    def test_FirstMiddleLastName(self):
        str = formatName("wolfgang", "mozart", "amadeus")
        self.assertEqual("Jane Eyre", str)
.F
======================================================================
FAIL: test_FirstMiddleLastName (__main__.NameTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "E:/项目/Python/PythonExp/TestName.py", line 12, in test_FirstMiddleLastName
    self.assertEqual("Jane Eyre", str)
AssertionError: 'Jane Eyre' != 'Wolfgang Amadeus Mozart'
- Jane Eyre
+ Wolfgang Amadeus Mozart


----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=1)

11.2 测试类

  • 除assertEqual(),unittest模块还提供了其他断言方法,这些断言方法只能在继承unittest.TestCase的类中使用。下面列出了6个常见的断言方法。
方法说明
assertEqual (a: any, b: any)核实a==b
assertNotEqual (a: any, b: any)核实a!=b
assertTrue (x: any)核实x为True
assertFalse (x: any)核实x为False
assertIn (item: any, container: Union[Iterable, Container])核实item在container中,container可以是列表、字典(核实键)、元组、字符串(核实子串)、文件对象(当对象为文本文件时,核实一行文本)等
assertNotIn (item: any, container: Union[Iterable, Container])核实item不在container中
  • 测试类与测试函数大致相同——大多数工作都是在测试类中的方法,但有些许不同。编写下面的类来说明测试类的方法。
class AnonymousSurvey():
    """
    收集匿名调查的答案
    """

    def __init__(self, question):
        self.question = question
        self.responses = []

    def collectResponses(self) -> None:
        print(self.question)
        print("Enter \"q\" at any time to quit.")
        while True:
            response = input("You Response: ")
            if response != "q":
                self.storeResponse(response)
            else:
                print("Thank you all for participating in the survey!")
                break

    def storeResponse(self, response: str) -> None:
        self.responses.append(response)

    def showResults(self) -> None:
        print("Survey Results:")
        for response in self.responses:
            print("- " + response)
  • 现在要测试storeResponse()方法。为了验证在一个人或者多个人回答问题时,程序都能将回答正确地保存进responses列表,可以编写下面的测试代码:
import unittest
from main import AnonymousSurvey


class SurveyTestCase(unittest.TestCase):
    def test_OneResponse(self):
        question = "What programming language did you first learn to use?"
        survey = AnonymousSurvey(question)
        survey.storeResponse("C++")
        self.assertIn("C++", survey.responses)

    def test_ThreeResponses(self):
        question = "What programming language did you first learn to use?"
        survey = AnonymousSurvey(question)
        responses = ["C++", "Java", "Python"]
        for response in responses:
            survey.storeResponse(response)
        for response in responses:
            self.assertIn(response, survey.responses)


unittest.main()

在这个测试用例里面,为每个单元测试都构造了一个AnonymousSurvey对象,而这两个对象的问题是相同的。可以预见,如果要进行大量测试,可能需要大量重复的工作。为此,可以借助unittest的setUp()方法。setUp()方法在任何单元测试开始之前运行,在setUp()方法中可以建立若干个对象,供之后所有的单元测试使用。使用setUp()的测试代码如下:

import unittest
from main import AnonymousSurvey


class SurveyTestCase(unittest.TestCase):
    def setUp(self):
        question = "What programming language did you first learn to use?"
        self.survey = AnonymousSurvey(question)
        self.responses = ["C++", "Java", "Python"]

    def test_OneResponse(self):
        self.survey.storeResponse(self.responses[0])
        self.assertIn(self.responses[0], self.survey.responses)

    def test_ThreeResponses(self):
        for response in self.responses:
            self.survey.storeResponse(response)
        for response in self.responses:
            self.assertIn(response, self.survey.responses)


unittest.main()

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值