第17章:Python TDD回顾与总结货币类开发
写在前面
这本书是我们老板推荐过的,我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后,我突然思考,对于测试开发工程师来说,什么才更有价值呢?如何让 AI 工具更好地辅助自己写代码,或许优质的单元测试是一个切入点。 就我个人而言,这本书确实很有帮助。第一次读的时候,很多细节我都不太懂,但将书中内容应用到工作中后,我受益匪浅。比如面对一些让人抓狂的代码设计时,书里的方法能让我逐步深入理解代码的逻辑与设计。 作为一名测试开发工程师,我想把学习这本书的经验分享给大家,希望能给大家带来帮助。因为现在工作中大多使用 Python 代码,所以我把书中JAVA案例都用 Python 代码进行了改写 。
问题背景说明
在完成货币类的一系列开发与优化后,对整个开发过程进行回顾和总结具有重要意义。通过回顾,可以总结经验教训,发现开发过程中的优点和不足之处,为未来的项目开发提供参考,同时也有助于加深对测试驱动开发流程和方法的理解和掌握,提高开发者的技术水平和开发效率。
完成货币类的一系列开发与优化后,对整个过程进行回顾总结,有助于加深对Python TDD的理解,为后续开发积累经验。
17.1 思路说明
回顾从简单的乘法功能测试到复杂的多币种货币运算实现的过程,分析测试驱动开发的流程、遇到的问题及解决方法,总结代码优化和设计的思路。
17.2 测试代码(综合回顾测试)
import unittestclass Bank:def __init__(self):# 存储货币兑换汇率的字典,键是 (from_currency, to_currency) 元组,值是汇率self.rates = {}def addRate(self, from_currency, to_currency, rate):# 添加一种货币到另一种货币的汇率self.rates[(from_currency, to_currency)] = ratedef rate(self, from_currency, to_currency):# 获取从 from_currency 到 to_currency 的汇率# 如果是相同货币,汇率为 1if from_currency == to_currency:return 1# 尝试从 rates 字典中获取汇率,如果没有则默认为 1return self.rates.get((from_currency, to_currency), 1)def reduce(self, source, to):# 将表达式(如 Sum 或 Money)转换为指定货币的 Money 对象if isinstance(source, Sum):# 如果是 Sum 类型,将加数和被加数都转换为目标货币,然后求和amount = source.augend.reduce(self, to).amount + source.addend.reduce(self, to).amountreturn Money(amount, to)elif isinstance(source, Money):# 如果是 Money 类型,根据汇率进行转换rate = self.rate(source.currency, to)return Money(source.amount / rate, to)class Expression:def reduce(self, bank, to):# 抽象方法,用于将表达式转换为指定货币的 Money 对象passclass Money(Expression):def __init__(self, amount, currency):# 金额self.amount = amount# 货币类型self.currency = currencydef plus(self, addend):# 实现加法操作,返回一个 Sum 对象return Sum(self, addend)def times(self, multiplier):# 实现乘法操作,返回一个新的 Money 对象,金额乘以乘数return Money(self.amount * multiplier, self.currency)def reduce(self, bank, to):# 将自身转换为指定货币的 Money 对象# 调用 bank 的 rate 方法获取汇率rate = bank.rate(self.currency, to)return Money(self.amount / rate, to)class Sum(Expression):def __init__(self, augend, addend):# 加数self.augend = augend# 被加数self.addend = addenddef reduce(self, bank, to):# 将 Sum 中的加数和被加数转换为指定货币,然后求和amount = self.augend.reduce(bank, to).amount + self.addend.reduce(bank, to).amountreturn Money(amount, to)class Dollar(Money):def __init__(self, amount):# 调用父类 Money 的构造函数,将货币类型设置为 USDsuper().__init__(amount, "USD")class Franc(Money):def __init__(self, amount):# 调用父类 Money 的构造函数,将货币类型设置为 CHFsuper().__init__(amount, "CHF")class TestAllCurrencyOperations(unittest.TestCase):def test_mixed_addition(self):bank = Bank()# 添加瑞士法郎到美元的汇率为 2bank.addRate("CHF", "USD", 2)# 创建 5 美元的对象five_dollars = Dollar(5)# 创建 10 瑞士法郎的对象ten_francs = Franc(10)# 将 5 美元和 10 瑞士法郎相加并转换为美元result = five_dollars.plus(ten_francs).reduce(bank, "USD")# 验证结果是否等于 10 美元self.assertEqual(result.amount, 10)# 验证结果的货币类型是否为美元self.assertEqual(result.currency, "USD")def test_dollar_multiplication(self):# 创建 5 美元的对象five_dollars = Dollar(5)# 将 5 美元乘以 3result = five_dollars.times(3)# 验证结果是否等于 15 美元self.assertEqual(result.amount, 15)# 验证结果的货币类型是否为美元self.assertEqual(result.currency, "USD")if __name__ == '__main__':unittest.main()
17.3 源码说明
这段综合测试代码涵盖了多币种加法运算和货币乘法运算的测试用例。通过回顾整个开发过程,我们从最初的简单功能逐步实现了复杂的货币运算系统。在这个过程中,不断地编写测试用例、实现功能代码、优化代码结构,遵循TDD的流程解决了各种问题,提高了代码的质量和可维护性。总结这些经验,能帮助我们在未来的Python开发中更好地应用TDD方法。
TDD过程中的关键要点回顾
在讲授和实践TDD的过程中,有几个关键要点反复出现,这些要点对于理解和应用TDD至关重要。
- 让测试工作的方式
1.1 伪实现:在TDD流程中,当编写完测试用例后,为了快速验证测试框架是否正常工作,以及测试用例是否能够按照预期运行,我们会采用伪实现的方式。这是一种临时性的代码实现,它并不追求功能的完整性和正确性,只是简单地让测试能够通过。例如,在开发货币类的乘法功能时,最初的times方法可能只是返回一个固定值,像这样:
class Dollar:def __init__(self, amount):self.amount = amountdef times(self, multiplier):return 0 # 伪实现,仅为使测试通过
通过这种方式,我们可以快速检查测试环境和测试用例的基本逻辑是否正确。如果此时测试能够顺利通过,说明测试框架和测试用例的基本设置没有问题;如果测试失败,我们可以先排查测试相关的问题,而不是纠结于功能代码的实现细节。一旦确认测试环节无误,我们再逐步完善功能代码,将伪实现替换为真正的功能实现。
1.2 三角测量:三角测量是一种通过多个类似的测试用例来逐步明确需求和实现通用解决方案的方法。当我们只有一个测试用例时,可能会编写一个仅适用于该特定情况的代码实现,这可能导致代码缺乏通用性。而三角测量通过增加更多相似但又有细微差异的测试用例,帮助我们发现代码中的共性和变化点,从而设计出更通用的解决方案。例如,在测试Dollar对象的乘法方法times时,我们最初可能只有一个测试用例:
def test_dollar_multiplication():five = Dollar(5)result = five.times(2)assert result == 10
此时,times方法的实现可能只是针对5 * 2这个特定情况编写的。为了确保times方法在各种输入下都能正确工作,我们可以增加更多测试用例:
def test_dollar_multiplication():five = Dollar(5)result = five.times(2)assert result == 10result = five.times(3)assert result == 15ten = Dollar(10)result = ten.times(4)assert result == 40
通过这些不同输入的测试用例,我们可以发现乘法运算的通用规律,进而实现一个能够适用于各种输入的times方法,避免返回常量值,使代码更具通用性和健壮性。
1.3 显式实现:显式实现是TDD过程的最终阶段,在这个阶段,我们根据之前编写的测试用例和通过三角测量明确的需求,实现完整、正确且符合业务逻辑的功能代码。此时的代码不仅要满足所有测试用例的要求,还要考虑代码的性能、可读性、可维护性等方面。例如,在货币类开发中,经过伪实现和三角测量阶段后,我们最终实现的times方法可能是这样的:
class Dollar:def __init__(self, amount):self.amount = amountdef times(self, multiplier):return self.amount * multiplier
这个实现是基于前面的测试和分析,明确了乘法运算的具体需求后完成的,它能够正确处理各种输入情况,并且符合货币金额乘法运算的实际逻辑。
-
消除重复:去掉测试代码和程序代码间的重复部分,是推进设计和开发的重要手段。在TDD开发过程中,随着功能的增加和代码量的增长,很容易出现重复代码。这些重复代码可能存在于测试用例中,也可能在功能代码中,或者在两者之间。重复代码不仅增加了代码量,还会使维护变得困难,因为一处修改可能需要在多个地方同步进行。通过重构,我们可以提取重复的代码片段,将其封装成独立的函数、方法或类,使代码更加简洁、易维护。例如,在测试不同货币类的乘法和加法运算时,如果多个测试用例中都有创建货币对象和进行基本断言的重复代码,我们可以将这些重复部分提取出来,封装成一个辅助函数或测试基类中的方法,减少代码冗余。
-
测试的控制力:当开发过程中遇到不确定因素时,要加强测试的控制力,如同在路面湿滑时增大摩擦力;而当情况明朗时,则可以加速前进,提高开发效率。在TDD中,测试的控制力体现在对测试用例的编写和执行上。当开发过程中遇到新的功能需求、复杂的业务逻辑或不确定的技术方案时,我们需要编写更多详细的测试用例,覆盖各种可能的情况,确保代码在各种条件下都能正确运行。这就好比在路面湿滑时,我们需要小心翼翼地控制车辆,增加摩擦力以确保安全行驶。例如,在实现多币种货币运算时,由于涉及汇率转换、不同货币对象的组合等复杂情况,我们需要编写大量测试用例来验证各种情况下的运算结果是否正确。而当我们对某个功能已经非常熟悉,代码实现也相对稳定时,我们可以适当减少测试用例的数量,或者采用更高效的测试策略,提高开发效率,就像在路况良好时可以适当加速行驶一样。但需要注意的是,即使在情况明朗时,也不能完全忽视测试,仍然要保证代码的质量和正确性。
相关文章:
第17章:Python TDD回顾与总结货币类开发
写在前面 这本书是我们老板推荐过的,我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后,我突然思考,对于测试开发工程师来说,什么才更有价值呢?如何让 AI 工具更好地辅助自己写代码,或许…...
opencv_KDTree_搜索介绍及示例
cv::flann::KDTreeIndexParams 说明,使用? cv::flann::KDTreeIndexParams 是 OpenCV 中用于配置 KD 树(K-Dimensional Tree)索引参数的类。KD 树是一种用于多维空间中的点搜索的数据结构,常用于最近邻搜索等问题。在…...
Windows 上安装 MongoDB 的 zip 包
博主介绍: 大家好,我是想成为Super的Yuperman,互联网宇宙厂经验,17年医疗健康行业的码拉松奔跑者,曾担任技术专家、架构师、研发总监负责和主导多个应用架构。 近期专注: RPA应用研究,主流厂商产…...
先进制造aps专题二十七 西门子opcenter aps架构分析
欧美的商业aps,主要就是sap apo,西门子opcenter aps,达索quintiq 从技术的层面,西门子aps是不如sap apo的,但是西门子aps是西门子数字化工厂产品的核心,有很多特色,所以分析 西门子aps主要分计划器和排产器两个部分 计…...
【数据分享】1929-2024年全球站点的逐年平均气温数据(Shp\Excel\无需转发)
气象数据是在各项研究中都经常使用的数据,气象指标包括气温、风速、降水、湿度等指标,其中又以气温指标最为常用!说到气温数据,最详细的气温数据是具体到气象监测站点的气温数据!本次我们为大家带来的就是具体到气象监…...
机器学习——什么是代价函数?
1.代价函数的定义 首先,提到代价函数是估计值和实际值的差,这应该是指预测值和真实值之间的差异,用来衡量模型的好坏。 在一元线性模型中,模型是直线,有两个参数,可能是斜率和截距。 通过调整这两个参数,让代价函数最小,这应该是说我们要找到最佳的斜率和截距,使得预测…...
docker 部署 MantisBT
1. docker 安装MantisBT docker pull vimagick/mantisbt:latest 2.先运行实例,复制配置文件 docker run -p 8084:80 --name mantisbt -d vimagick/mantisbt:latest 3. 复制所需要配置文件到本地路径 docker cp mantisbt:/var/www/html/config/config_inc.php.…...
02内存结构篇(D1_自动内存管理)
目录 一、内存管理 1. C/C程序员 2. Java程序员 二、运行时数据区 1. 程序计数器 2. Java虚拟机栈 3. 本地方法栈 4. Java堆 5. 方法区 运行时常量池 三、Hotspot运行时数据区 四、分配JVM内存空间 分配堆的大小 分配方法区的大小 分配线程空间的大小 一、内存管…...
Centos 8 交换空间管理
新增swap 要增加 Linux 系统的交换空间,可以按照以下步骤操作: 1. 创建一个交换文件 首先,选择文件路径和大小(例如,增加 1 GB 交换空间)。 sudo fallocate -l 1G /swapfile如果 fallocate 不可用&…...
“深入浅出”系列之数通篇:(5)TCP的三次握手和四次挥手
TCP(传输控制协议)的三次握手和四次挥手是TCP连接建立和释放的过程。 一、TCP三次握手 TCP三次握手是为了建立可靠的连接,确保客户端和服务器之间的通信能力。具体过程如下: 第一次握手:客户端向服务器发送一个带有…...
接口测试及接口测试常用的工具
🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 首先,什么是接口呢? 接口一般来说有两种,一种是程序内部的接口,一种是系统对外的接口。 系统对外的接口ÿ…...
使用rpc绕过咸鱼sign校验
案例网站是咸鱼 找到加密函数i(),发现参数是由token时间戳appkeydata构成的 js客户端服务 考虑到网站可能有判断时间戳长短而让请求包失效的可能,我们请求包就直接用它的方法生成 下面我们先把token和h置为键值对tjh123 再把方法i()设为全局变量my_…...
NPC与AI深度融合结合雷鸟X3Pro AR智能眼镜:引领游戏行业沉浸式与增强现实新纪元的畅想
if… NPC(非玩家角色)与AI(人工智能)的深度融合,正引领游戏行业迈向一个全新的沉浸式与增强现实(AR)相结合的新时代。这一创新不仅预示着游戏体验的质变,更可能全面革新游戏设计与叙…...
【物联网】ARM核介绍
文章目录 一、芯片产业链1. CPU核(1)ARM(2)MIPS(3)PowerPc(4)Intel(5)RISC-V 2. SOC芯片(1)主流厂家(2)产品解决方案 3. 产品 二、ARM核发展1. 不同架构的特点分析(1)VFP(2)Jazelle(3)Thumb(4)TrustZone(5)SIMD(6)NEON 三、ARM核(ARMv7)工作模式1. 权限级别(privilege level)2.…...
Android系统定制APP开发_如何对应用进行系统签名
前言 当项目开发需要使用系统级别权限或frame层某些api时,普通应用是无法使用的,需要在AndroidManifest中配置sharedUserId: AndroidManifest.xml中的android:sharedUserId“android.uid.system”,代表的意思是和系统相同的uid&a…...
Tesla Free-Fall Attack:特斯拉汽车网络安全事件纪要
Tesla Free-Fall Attack:特斯拉汽车网络安全事件纪要 1. 引言 Tesla Free-Fall Attack 是由腾讯科恩实验室(Tencent Keen Security Lab)于2016年9月对特斯拉Model S汽车实施的一次远程攻击事件,揭示了汽车网络安全的严重漏洞&am…...
网络安全工程师学习路线
https://www.processon.com/view/link/6584f06465b7eb6189e99508 1、HTML基本语言 常用标签、表单、上传页面、登录页面、超链接2、javascript基本语法 变量、函数、流程控制语法、post请求、ajax请求、输入数据到页面、文件上传3、mysql基本用法 增删改查 infromation_sch…...
分区和分表有什么区别?
数据库中数据量过多,表太大的时候,不仅可以做分库分表,还可以做表分区,分区和分表类似,都是按照一定的规则将一张大表进行分解。 听上去好像也差不多,不就是将表拆分吗?那具体有什么差别呢&…...
C#,入门教程(01)—— Visual Studio 2022 免费安装的详细图文与动画教程
通过本课程的学习,你可以掌握C#编程的重点,享受编程的乐趣。 在本课程之前,你无需具备任何C#的基础知识,只要能操作电脑即可。 不过,希望你的数学不是体育老师教的。好的程序是数理化的实现与模拟。没有较好的数学基础…...
简述mysql 主从复制原理及其工作过程,配置一主两从并验证。
MySQL 主从同步是一种数据库复制技术,它通过将主服务器上的数据更改复制到一个或多个从服务器,实现数据的自动同步。 主从同步的核心原理是将主服务器上的二进制日志复制到从服务器,并在从服务器上执行这些日志中的操作。 MySQL主从同步是基…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
