第21章 走进 xUnit:测试驱动开发的关键工具(又续)

写在前面


这本书是我们老板推荐过的,我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后,我突然思考,对于测试开发工程师来说,什么才更有价值呢?如何让 AI 工具更好地辅助自己写代码,或许优质的单元测试是一个切入点。 就我个人而言,这本书确实很有帮助。第一次读的时候,很多细节我都不太懂,但将书中内容应用到工作中后,我受益匪浅。比如面对一些让人抓狂的代码设计时,书里的方法能让我逐步深入理解代码的逻辑与设计。 作为一名测试开发工程师,我想把学习这本书的经验分享给大家,希望能给大家带来帮助。因为现在工作中大多使用 Python 代码,所以我把书中JAVA案例都用 Python 代码进行了改写 。


在前面的博客中,我们深入探讨了xUnit测试框架里测试的资源清理、日志记录以及tearDown方法的实现等内容。接下来,我们将继续探索书中关于测试计数以及处理测试失败等方面的知识,并通过完整的示例代码来呈现。

测试计数功能的实现

目标与需求

我们打算实现一个功能,确保无论测试方法出现何种异常,tearDown方法都会被调用,并且希望捕获这些异常并记录到测试结果中。同时,我们希望TestCase.run()方法返回一个TestResult对象,用于记录测试运行的结果,包括运行的测试数目和失败的测试数目等信息。

代码实现过程

  1. 伪实现阶段
    我们先从伪实现开始,定义TestResult类并提供一个简单的summary方法:
python 复制代码
class TestResult:
    def summary(self):
        return "1 run, 0 failed"

同时,更新TestCase类的run方法,使其返回TestResult对象:

python 复制代码
class TestCase:
    def __init__(self, name):
        self.name = name

    def setUp(self):
        pass

    def tearDown(self):
        pass

    def run(self):
        self.setUp()
        method = getattr(self, self.name)
        method()
        self.tearDown()
        return TestResult()
  1. 完善TestResult类
    为了准确记录测试数目,我们需要对TestResult类进行改进。将runCount初始化为0,每运行一个测试就将其加1:
python 复制代码
class TestResult:
    def __init__(self):
        self.runCount = 0

    def testStarted(self):
        self.runCount = self.runCount + 1

    def summary(self):
        return "%d run, 0 failed" % self.runCount
  1. 更新TestCase类的run方法
    在TestCase类的run方法中,调用testStarted方法来更新测试计数:
python 复制代码
class TestCase:
    def __init__(self, name):
        self.name = name

    def setUp(self):
        pass

    def tearDown(self):
        pass

    def run(self):
        result = TestResult()
        result.testStarted()
        self.setUp()
        method = getattr(self, self.name)
        method()
        self.tearDown()
        return result
  1. 测试失败的情况
    为了测试测试失败时的情况,我们编写一个新的测试testFailedResult,以及在WasRun类中定义一个会抛出异常的testBrokenMethod方法:
python 复制代码
class TestCaseTest(TestCase):
    def testFailedResult(self):
        test = WasRun("testBrokenMethod")
        result = test.run()
        assert "1 run, 1 failed" == result.summary()


class WasRun:
    def __init__(self, name):
        self.name = name
        self.wasRun = None
        self.log = ""

    def setUp(self):
        self.wasRun = None
        self.log = "setUp "

    def testMethod(self):
        self.wasRun = 1
        self.log = self.log + "testMethod"

    def tearDown(self):
        self.log = self.log + " tearDown"

    def testBrokenMethod(self):
        raise Exception

目前,上述测试会存在问题,因为我们还没有捕获由WasRun.testBrokenMethod抛出的异常,并将其作为测试失败的结果记录到测试结果中。

完整示例代码

python 复制代码
class TestResult:
    def __init__(self):
        self.runCount = 0
        self.failureCount = 0

    def testStarted(self):
        self.runCount = self.runCount + 1

    def testFailed(self):
        self.failureCount = self.failureCount + 1

    def summary(self):
        return "%d run, %d failed" % (self.runCount, self.failureCount)


class TestCase:
    def __init__(self, name):
        self.name = name

    def setUp(self):
        pass

    def tearDown(self):
        pass

    def run(self):
        result = TestResult()
        result.testStarted()
        self.setUp()
        try:
            method = getattr(self, self.name)
            method()
        except:
            result.testFailed()
        self.tearDown()
        return result


class WasRun:
    def __init__(self, name):
        self.name = name
        self.wasRun = None
        self.log = ""

    def setUp(self):
        self.wasRun = None
        self.log = "setUp "

    def testMethod(self):
        self.wasRun = 1
        self.log = self.log + "testMethod"

    def tearDown(self):
        self.log = self.log + " tearDown"

    def testBrokenMethod(self):
        raise Exception


class TestCaseTest(TestCase):
    def testFailedResult(self):
        test = WasRun("testBrokenMethod")
        result = test.run()
        assert "1 run, 1 failed" == result.summary()

本章小结

回顾本章内容,我们完成了以下重要任务:

  • 编写了一个伪实现,并逐步将其完善,以变量代替常量来准确记录测试运行的相关信息。
  • 编写了针对测试功能的测试用例,即测试的测试,用于验证测试框架的正确性。
  • 针对测试运行失败的情况编写了专门的测试用例,虽然目前还存在异常捕获的问题,但为后续完善测试框架指明了方向。

通过不断地深入研究和实践,我们对xUnit测试框架的理解更加全面,在测试驱动开发的道路上又迈进了一步。后续我们将继续探索如何更好地处理测试失败等情况,进一步提升测试框架的稳定性和可靠性。

相关推荐
sukalot2 小时前
window 显示驱动开发-线程同步和 TDR
驱动开发
sukalot5 小时前
window 显示驱动开发-配置内存段类型
驱动开发
qq_288086977 小时前
嵌入式驱动学习
驱动开发
__Benco9 小时前
OpenHarmony平台驱动开发(十),MMC
人工智能·驱动开发·harmonyos
__Benco11 小时前
OpenHarmony平台驱动开发(十一),PIN
人工智能·驱动开发·harmonyos
sukalot1 天前
window 显示驱动开发-用户模式显示驱动程序的线程模型
驱动开发
程序员JerrySUN1 天前
驱动开发硬核特训 · Day 28(上篇):pinctrl 子系统详解与实战分析
linux·驱动开发
程序员JerrySUN1 天前
驱动开发硬核特训 · Day 30(上篇):深入理解 I2C 总线驱动模型(以 at24 EEPROM 为例)
linux·开发语言·驱动开发
天夏已微凉1 天前
1.2 Linux音频系统发展历程与关键技术演进
linux·c语言·驱动开发·音视频
__Benco2 天前
OpenHarmony平台驱动开发(九),MIPI DSI
人工智能·驱动开发·harmonyos