当前位置: 首页 > article >正文

第18章 走进xUnit:测试驱动开发的关键工具

写在前面


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

在软件开发领域,测试驱动开发(TDD)是保障代码质量的有效实践,xUnit作为TDD常用的测试框架家族,蕴含着丰富的逻辑与应用价值。接下来,我们通过更完整的代码示例深入剖析其工作原理。

测试驱动开发工具的独特性

利用测试工具自身运行测试来驱动开发,如同给自己实施精细的外科手术,这正是xUnit测试框架的特别之处。在缺乏现成完美框架的情况下,开发者需亲自验证每一步开发,确保代码符合预期。

代码示例

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

    def setup(self):
        self.wasRun = 0
        print("setup")

    def testMethod(self):
        print("testMethod")
        self.wasRun = 1

    def teardown(self):
        print("teardown")


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

    def setUp(self):
        pass

    def tearDown(self):
        pass

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


class TestResult:
    def __init__(self):
        self.runCount = 0
        self.errorCount = 0

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

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

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


class TestCaseTest(TestCase):
    def setUp(self):
        self.result = TestResult()

    def testTemplateMethod(self):
        test = WasRun("testMethod")
        test.run(self.result)
        assert ("setup testMethod teardown" == test.log)

    def testResult(self):
        test = WasRun("testMethod")
        test.run(self.result)
        assert ("1 run, 0 failed" == self.result.summary())

    def testFailedResult(self):
        test = WasRun("testMethod")
        test.testMethod = lambda: 1 / 0
        test.run(self.result)
        assert ("1 run, 1 failed" == self.result.summary())

    def testFailedResultFormatting(self):
        result = TestResult()
        result.testStarted()
        result.testFailed()
        assert ("1 run, 1 failed" == result.summary())


if __name__ == "__main__":
    suite = TestCaseTest("testTemplateMethod")
    result = suite.run()
    print(result.summary())

代码逻辑推理

WasRun类

  • 初始化__init__方法设置wasRun属性为None,记录测试方法是否被运行,同时保存测试方法名称。
  • setup方法:将wasRun设置为0,代表测试开始前的初始状态,并打印"setup",模拟测试前的准备工作。
  • testMethod方法:打印"testMethod",代表测试方法的执行逻辑,并将wasRun设置为1,标识测试方法已被执行。
  • teardown方法:打印"teardown",模拟测试后的清理工作。

TestCase类

  • 初始化__init__方法保存测试用例名称。
  • setUp和tearDown方法:默认实现为空,可由子类重写以进行测试前准备和测试后清理。
  • run方法:接收一个TestResult对象(若未传入则创建新的),先调用testStarted方法标记测试开始,接着执行setUp,然后尝试调用指定名称的测试方法,若方法执行中抛出异常则调用testFailed记录失败,最后执行tearDown,并返回TestResult对象。

TestResult类

  • 初始化:设置runCount(测试运行次数)为0,errorCount(测试失败次数)为0。
  • testStarted方法:每次测试开始时将runCount加1。
  • testFailed方法:测试失败时将errorCount加1。
  • summary方法:返回测试运行和失败次数的摘要信息。

TestCaseTest类

继承自TestCase类,包含多个测试方法:

  • testTemplateMethod:测试TestCase类的模板方法逻辑,创建WasRun实例并运行测试,验证测试过程中的日志记录是否符合预期。
  • testResult:验证TestResult类在正常测试情况下统计结果的正确性。
  • testFailedResult:故意使测试方法抛出异常,验证TestResult类在测试失败时统计结果的正确性。
  • testFailedResultFormatting:单独测试TestResult类在测试失败时摘要信息的格式化是否正确。

if __name__ == "__main__"块中,创建TestCaseTest实例并运行测试,打印测试结果摘要。通过这些代码和逻辑,我们能清晰看到xUnit风格的测试框架如何组织和运行测试用例,以及处理测试结果。

已完成与待完成事项

在之前的讨论中,我们明确了完善的测试框架包含以下关键待办事项:

  • Invoke setUp first:在测试执行前首先调用设置方法,用于初始化测试所需的环境、资源等,为测试的顺利进行做好准备。
  • Invoke tearDown afterwards:在测试结束后调用清理方法,用于释放测试过程中占用的资源,如关闭文件、数据库连接等,确保测试环境恢复原状。
  • Invoke tearDown even if the test method fails:即使测试方法执行失败,也要调用清理方法,保证无论测试结果如何,都能正确处理测试过程中产生的资源,维持测试环境的一致性和稳定性。
  • Run multiple tests:具备运行多个测试的能力,能够将多个测试用例组织起来并依次执行,提高测试效率,满足项目中大量测试用例的执行需求。
  • Report collected results:收集并报告测试结果,提供详细的测试信息,包括哪些测试通过、哪些失败,以及失败的原因等,帮助开发者快速定位和解决问题。

在当前的示例代码中,我们仅仅初步实现了部分基础功能:

  • 创建测试用例类:定义了TestCase类,用于封装测试方法和相关的测试逻辑。
  • 实现测试执行逻辑:在TestCase类中实现了run方法,能够执行单个测试方法,并在执行前后预留了setUptearDown方法的调用位置,不过目前这两个方法为空实现。
  • 统计测试结果:创建了TestResult类,用于统计测试运行的次数和失败的次数,能够生成简单的测试结果摘要。
  • 测试功能验证:编写了TestCaseTest类,对TestCaseTestResult类的关键功能进行了简单的测试验证,确保基本的测试流程和结果统计功能正常。

下一章节,我们将聚焦于这些待完成事项,深入探讨如何在实际项目中进一步完善xUnit测试框架的应用,提升测试效率和质量。


http://www.kler.cn/a/520107.html

相关文章:

  • Elastic Agent 对 Kafka 的新输出:数据收集和流式传输的无限可能性
  • 每日 Java 面试题分享【第 13 天】
  • 二叉搜索树中的众数(力扣501)
  • 网盘资源查找工具---AI功能
  • 如何在data.table中处理缺失值
  • HTB:Support[WriteUP]
  • Docker 从零开始掌握容器化技术
  • 数据融合的经典模型:早期融合、中期融合与后期融合的对比
  • appium自动化环境搭建
  • 12.Shader开发概述
  • 高并发压力测试
  • 【go语言】map 和 list
  • Verilog边沿检测
  • 16.好数python解法——2024年省赛蓝桥杯真题
  • 谈谈对JavaScript 中的事件冒泡(Event Bubbling)和事件捕获(Event Capturing)的理解
  • 从63 秒到 0.482 秒:深入剖析 MySQL 分页查询优化
  • pipeline快速将数据存入redis
  • 【含代码】逆向获取 webpack chunk 下的__webpack_require__ 函数,获悉所有的模块以及模块下的函数
  • wordpress调用指定ID页面的链接
  • Maven下载与配置
  • SYN Flooding的攻击原理
  • 微服务网关鉴权之sa-token
  • 问题修复记录:Linux docker 部署 dify,无法调用宿主机本地服务
  • 计算机网络 (59)无线个人区域网WPAN
  • Stable Diffusion 3.5 介绍
  • 基于STM32单片机设计的宠物喂食监控系统