先测试再开发?TDD测试驱动开发了解一下?

简介: TDD测试驱动开发概念以及简单使用

1、什么是TDD

我第一次接触TDD这个概念,是在<<代码整洁之道>>中,作者鲍勃大叔在书中,写了一些关于测试代码的代码规范,其实就提到了有关TDD三定律:

- 定律一: 在编写不能通过的单元测试前,不可编写生产代码
- 定律二: 只可编写刚好无法通过的单元测试,不能编译也算不能通过
- 定律三:只可编写刚好足以通过当前失败测试的生存代码

我第一次读到这三个定律时,不能说是毫无头绪,只能说是一脸懵逼。
在这里插入图片描述
完全不知道作者想表达啥意思,也没有案例代码。
对此,我不得不网上查阅的很多相关文章,最后总结出来。

TDD测试驱动开发,就是先写测试用例,再去开发功能。
这里测试驱动开发里的驱动是做动词,不是名词

好了,现在如果别人问你TDD是什么,你就可以直接这样告诉他。

2、传统开发方式

我们传统开发一个功能是这么开发的?
传统编码方式

  • 需求分析,想不清楚细节,管他呢,先开始写
  • 发现需求细节不明确,去跟业务人员确认
  • 确认好几次终于写完所有逻辑
  • 运行起来测试一下,靠,果然不工作,调试
  • 调试好久终于工作了
  • 转测试,QA 测出 bug,debug, 打补丁
  • 终于,代码可以工作了
  • 一看代码烂的像坨屎,不敢动,动了还得手工测试,还得让 QA 测试,还得加班...

传统的开发方式,都是以开发为主,直接开始编写代码,代码出了问题,再去改,多改几次,你就会觉得这代码简直就是屎山,想重构一下,又怕出新的问题。

3、TDD步骤

而TDD测试驱动开发是怎么做的呢?

TDD要求我们先根据需求去拆分任务,把一个大的任务拆分位各个模块,也就是一个个的函数,我们再去为这些函数去编写最小的测试,再去写能让这个最小的测试通过的最小的实现。
TDD的生命周期图如下。
在这里插入图片描述

这样做的好处是:

  • 1、有助于我们提前澄清需求
  • 2、可以通过单元测试断言的诊断机制快速得出反馈
  • 3、当我们写完了所有的需求,会发现所有的需求都会被测试覆盖了

4、举个例子

正所谓,光说不练,假把式;下来我们来整个简单的例子去理解一下测试驱动开发;
假如我需要写个功能,分析用户上传的文本中,每个单词的数量,并且按照数量倒序排序,这个应该怎么实现:
比如说文本如下:

Hello world
Hello CSDN
Hello Boy
My name is Boy 
is is 

那输出就是:

Hello 3
is 3
Boy 2
world 1
CSDN 1
My 1 
name 1

如果是新手或者是完全不懂代码设计的人拿到这样的功能,可能会这样写:

 public static void main(String[] args) throws Exception{
        String words = "";
        File file=new File("word.txt");
        Scanner sc=new Scanner(file);
        while(sc.hasNextLine()){
            String line=sc.nextLine();
            words = words + line + " ";
        }
        System.out.println(words);

        String[] wordArrays =  words.split(" ");

        HashMap<String,Integer> hashMap = new HashMap<>();

        for(int i=0;i<wordArrays.length;i++){
            Set<String> wordSet = hashMap.keySet();
            if(wordSet.contains(wordArrays[i])){
                Integer number=hashMap.get(wordArrays[i]);
                number++;
                hashMap.put(wordArrays[i],number);
            }else{
                hashMap.put(wordArrays[i],1);
            }
        }
        System.out.println("统计单词------------------");


        List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(hashMap.entrySet()); //转换为list
        list.sort(new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                return o2.getValue().compareTo(o1.getValue());
            }
        });
        System.out.println(list);       
    }

好了,写完了,让我们运行一下:
在这里插入图片描述
运行结果貌似也没有问题,好了提交代码。
真的没有问题吗?统计单词的数目也没有问题,但是,如果后期,你要对这段代码做维护,要去修改这段代码,这段代码读起来是什么感觉?在我看来,这段代码,就是屎山。
代码里几乎完全没有注释,读这段代码,得从头开始往下读,如果其中一段代码出了问题,你必须在整段代码中寻找错误,非常浪费时间。

让我们来试试看TDD的写法,TDD要求首先要把一个功能,去拆分分成各个小功能,然后去为这些小功能写测试用例。
这个统计单词数目的代码应该怎么拆分,试着拆分成小功能一下(这里要注意一下,同样的功能,在拆分模块的时候,不同的人选择的拆分方法可能不同,一千个人里有一千个哈姆雷特,一千个人里也有一千种拆分方法)

flowchart TD
    从外部文件读取单词到字符串--> 分隔单词到数组-->用haspmap分组-->按照排序规则进行输出

拆分好后,我们就可以为这些功能编写测试用例了,
我们先编写测试用例,用assert断言测试用例是否通过,运行,我们可以看出,方法还没有进行开发,显示未通过。
在这里插入图片描述

这一步,就是TDD定律二中规定的

- 定律二: 只可编写刚好无法通过的单元测试,不能编译也算不能通过

下一步要做什么?我们看定律一

- 定律一: 在编写不能通过的单元测试前,不可编写生产代码

定律一反过来是什么意思,不就是编写好不能通过的单元测试后,就可以开始编写生产代码了吗?
于是开始编写生产代码进行测试
在这里插入图片描述

在这里,我们编写好了方法,在执行测试用例后,显示绿色,代表测试用例通过。
这时候又满足了第三定律

- 定律三:只可编写刚好足以通过当前失败测试的生存代码

我们的测试用例,专门测试一个小的功能,只为了通过这个方法。

下一步我们再重复以上步骤,去TDD其他模块。
直到TDD完所有模块,我们的功能就开发完了。
代码如下:

 public static void main(String[] args) throws Exception {
        //读取文件
        File file=new File("word.txt");
        String words = readFile(file);
        String[] s1 = words.split(" ");
        //单词记录到hashmap
        HashMap<String, Integer> stringIntegerHashMap = groupHashMap(s1);
        //排序
        List<Map.Entry<String, Integer>> entries = orderHashMap(stringIntegerHashMap);
        //输出
        System.out.println(entries);
    }

方法的代码太长,太展篇幅就不粘贴了,你看我们新的main方法,代码就比较简介,如果出了问题,只可能在这三个方法中其中,我们可以快速定位到方法中去,并且可以用之前编写的测试用例进行测试。

5、总结

关于TDD测试驱动开发,我感觉精髓就是对功能进行拆分,用测试用例去测试功能,我相信很多人,都不会去编写测试用例,代码写好后,就去页面上点几下,其实这是不太好的。因为如果这里的功能改动比较频繁,你每次去页面上通过点击的方式测试功能,你得打开浏览器,登录地址,寻找IP,为功能配置参数,这一套下来,真的非常耗费时间。
一次如果5分钟,10次就是50分钟。
而TDD建议的是什么?建议通过测试用例的方式去测试,它要求你必须编写好测试用例后再去写代码,这样就能保住,你每个小功能,都有一个测试用例,这样,之后你改一个地方,只要找到这个地方所对应的测试用例就能测试了,非常方便。
当然,TDD这种开发方法其实弊端也是很明显的,比如,大多数程序员,其实是怎么做测试的?就是直接重启项目,去页面上看看,功能对不对,测试用例?那是什么?我不是开发吗,我又不是测试。我去页面点几下测试,可能只需要几分钟,我去配置测试用例,八成等得二十分钟,所以大多数程序员可能还是会选择通过页面点击的方式去测试。

测试用例真的是没有必要的吗?如果你去新建一个Maven项目,你会发送,test目录和main目录是同一级别的
在这里插入图片描述
我相信在设计的时候,可能设计者(设计Maven的程序员肯定是大佬中的大佬),也是认为测试用例是非常重要的,才会把test目录放在这个位置吧。

相关文章
|
3月前
|
缓存 运维 数据库
【测试人员兼职指南】利用专业技能:如何从测试转向开发赚钱
本文分享了作者作为测试人员如何利用专业技能转向开发来兼职赚钱的经验,包括分析和解决登录页面跳转、避免重复账号注册、用户登录后首页显示用户名以及添加退出功能等问题,并提供了Django项目中使用sqlite3数据库和后台管理的扩展技巧。
129 1
【测试人员兼职指南】利用专业技能:如何从测试转向开发赚钱
|
3月前
|
Java 测试技术 开发者
在软件开发中,测试至关重要,尤以单元测试和集成测试为然
在软件开发中,测试至关重要,尤以单元测试和集成测试为然。单元测试聚焦于Java中的类或方法等最小单元,确保其独立功能正确无误,及早发现问题。集成测试则着眼于模块间的交互,验证整体协作效能。为实现高效测试,需编写可测性强的代码,并选用JUnit等合适框架。同时,合理规划测试场景与利用Spring等工具也必不可少。遵循最佳实践,可提升测试质量,保障Java应用稳健前行。
49 1
|
21天前
|
测试技术 C# 数据库
C# 一分钟浅谈:测试驱动开发 (TDD) 实践
【10月更文挑战第18天】测试驱动开发(TDD)是一种软件开发方法论,强调先编写测试代码再编写功能代码,以确保代码质量和可维护性。本文从 TDD 的基本概念入手,详细介绍了其核心步骤——编写测试、运行测试并失败、编写代码使测试通过,以及“红绿重构”循环。文章还探讨了 TDD 的优势,包括提高代码质量、促进设计思考、减少调试时间和文档化。此外,文中分析了常见问题及解决方案,如测试覆盖率不足、测试代码过于复杂、忽视重构和测试依赖过多,并通过一个简单的计算器类的代码案例,展示了 TDD 的实际应用过程。
32 1
|
1月前
|
测试技术 网络安全
什么是软件测试? 软件测试都有什么岗位 ?软件测试和调试的区别? 软件测试和开发的区别? 一位优秀的测试人员应该具备哪些素质? 软件测试等相关概念入门篇
文章全面介绍了软件测试的基本概念、目的、岗位分类、与开发和调试的区别,并阐述了成为优秀测试人员应具备的素质和技能。
170 1
什么是软件测试? 软件测试都有什么岗位 ?软件测试和调试的区别? 软件测试和开发的区别? 一位优秀的测试人员应该具备哪些素质? 软件测试等相关概念入门篇
|
3天前
|
安全 测试技术 持续交付
云计算时代的软件开发与测试:高效、灵活、可扩展
云计算时代的软件开发与测试:高效、灵活、可扩展
|
28天前
|
人工智能 监控 测试技术
云应用开发平台测试
云应用开发平台测试
44 2
|
1月前
|
敏捷开发 测试技术
开发模型(瀑布、螺旋、scrum) 和 测试模型(V、W)、增量和迭代、敏捷(思想)及敏捷开发 scrum
文章详细介绍了软件开发过程中的不同开发模型(瀑布、螺旋、Scrum)和测试模型(V模型、W模型),以及增量和迭代的概念,最后阐述了敏捷思想及其在敏捷开发(如Scrum)中的应用。
58 0
开发模型(瀑布、螺旋、scrum) 和 测试模型(V、W)、增量和迭代、敏捷(思想)及敏捷开发 scrum
|
2月前
|
测试技术 持续交付 UED
软件测试的艺术与科学:平衡创新与质量的探索在软件开发的波澜壮阔中,软件测试如同灯塔,指引着产品质量的方向。本文旨在深入探讨软件测试的核心价值,通过分析其在现代软件工程中的应用,揭示其背后的艺术性与科学性,并探讨如何在追求技术创新的同时确保产品的高质量标准。
软件测试不仅仅是技术活动,它融合了创造力和方法论,是软件开发过程中不可或缺的一环。本文首先概述了软件测试的重要性及其在项目生命周期中的角色,随后详细讨论了测试用例设计的创新方法、自动化测试的策略与挑战,以及如何通过持续集成/持续部署(CI/CD)流程优化产品质量。最后,文章强调了团队间沟通在确保测试有效性中的关键作用,并通过案例分析展示了这些原则在实践中的应用。
71 1
|
2月前
|
测试技术 UED 开发者
软件测试的艺术:从代码审查到用户反馈的全景探索在软件开发的宇宙中,测试是那颗确保星系正常运转的暗物质。它或许不总是站在聚光灯下,但无疑是支撑整个系统稳定性与可靠性的基石。《软件测试的艺术:从代码审查到用户反馈的全景探索》一文,旨在揭开软件测试这一神秘面纱,通过深入浅出的方式,引领读者穿梭于测试的各个环节,从细微处着眼,至宏观视角俯瞰,全方位解析如何打造无懈可击的软件产品。
本文以“软件测试的艺术”为核心,创新性地将技术深度与通俗易懂的语言风格相结合,绘制了一幅从代码审查到用户反馈全过程的测试蓝图。不同于常规摘要的枯燥概述,这里更像是一段旅程的预告片,承诺带领读者经历一场从微观世界到宏观视野的探索之旅,揭示每一个测试环节背后的哲学与实践智慧,让即便是非专业人士也能领略到软件测试的魅力所在,并从中获取实用的启示。
|
3月前
|
测试技术 API
软件测试:Postman 工具的使用。开发及测试均需要掌握的测试工具
这篇文章详细介绍了Postman工具的各个模块功能,包括创建请求、集合、环境、自动化测试等,并解释了如何使用Postman进行GET、POST、PUT和DELETE等常见HTTP请求的测试。