敏捷开发
How to do TDD?
1、写一个空方法。 2、写一个测试程序(单元测试用例)。 3、让程序编译通过。 4、运行测试程序,发现不能运行。(红条) 5、让测试程序可以运行。(绿条) 6、消除重复设计,优化设计结构。(绿条) 7、重构
确定业务
1、用户可以选择付费月份为1、2、3个月 2、用户选择1个月最多可用1个红包 3、用户选择2个月最多可用2个红包 4、用户选择3个月最多可用3个红包
Agent
从一句大师的话开始
编写单元测试是在进行验 证,更是在进行设计。同 样,它更是在编写文档。
心灵震憾
一段时间的学习,让我的内心受到了深深的震撼。我们原来的方法居然如此的笨。
以前我面对测试先行这一名字时,最大的疑问就是"程序都还没有写出来, 测试 什么呀!"。
后来一想,其实这是一个泥瓦匠都明白的道理,却是自己在画地为牢。我们来看 看两个不同泥瓦匠是如何工作的。
assertEquals(0, cm.getNumOfCoupsCanUse(1, assertEquals(1, cm.getNumOfCoupsCanUse(1, assertEquals(1, cm.getNumOfCoupsCanUse(1, assertEquals(2, cm.getNumOfCoupsCanUse(2, assertEquals(3, cm.getNumOfCoupsCanUse(3, assertEquals(1, cm.getNumOfCoupsCanUse(3,
对待缺陷的态度
服务端push让修复后的版本发布代价 大大降低 可靠性和性能可以通过集群或者冗余 运算的方式部分解决 在最坏的情况下,回滚吧!
提高产品的质量
为什么要敏捷?
在快速发布的环境中
缺陷并非总那么可怕
快速发现缺陷
快速修复bug
缺陷从发现到修复并部署的周期可以被控制的很短
敏捷开发方法
测试驱动开发的精髓
将测试方案设计工作提前,在编写代码之前先做这一项工作;
从测试的角度来验证设计,推导设计;
将测试方案当作行为的准绳,有效地利用其检验代码编写的每一步,实时验 证其正确性,实现软件开发过程的"小步快走"。
What is TDD?
Test Driven Development(测试驱动开发) 测试先行。 持续重构。 测试驱动开发是一种在极限编程(XP)中 处于核心地位的技术。
Alibaba 的测试情况
80%开发人员认为测试就是测试人员的事情 测试就是不断的发现bug 无建立好的持续集成框架 80%的项目无考虑可测试性,部分是提交了测 试之后再考虑 单元测试覆盖率低 有codereview,但无结对
今天,我们开发所必须要做的
意识到提高产品的质量也是开发的重要责任 引用敏捷开发的测试驱动开发和结对,提高产 品质量 帮助测试人员建立持续集成框架、验收测试的 标准 可测试性的设计
1、写一个空方法
public class CouponManagerImpl { /** * 根据选择充值月数和拥有的最大红包数,取得可用红包数 * @param months 充值月数 * @param totalCoups 拥有的最大红包数 * @return 可用红包数 */ public int getNumOfCoupsCanUse(int months, int totalCoups) { // TODO 完成该方法 return 0; } }
assertEquals(0, cm.getNumOfCoupsCanUse(1, 0)); assertEquals(1, cm.getNumOfCoupsCanUse(1, 1)); assertEquals(1, cm.getNumOfCoupsCanUse(1, 5)); assertEquals(2, cm.getNumOfCoupsCanUse(2, 5)); assertEquals(3, cm.getNumOfCoupsCanUse(3, 5)); assertEquals(1, cm.getNumOfCoupsCanUse(3, 1)); assertEquals(1, cm.getNumOfCoupsCanUse(6, 1)); assertEquals(3, cm.getNumOfCoupsCanUse(6, 5));
敏捷开发 之测试驱动开发
Agent
为什么要敏捷?
用户体验
互联网产品的关注点
创新
为用户创造价值
为什么要敏捷?
建立在用户体验基础上的创新
小步快走 微创新 快速获取用户反馈
互联网产品的开发
为什么要敏捷?
快意味着一切
快速实现的能力 快速发布的能力 快速修复的能力
为什么要敏捷?
互联网产品中的缺陷同样致命,但 是修复成本相对较低
4、优化程序
public int getNumOfCoupsCanUse(int months, int totalCoups) { if (months < 1 || months > 3) { return 0; } return (totalCoups >= months) ? months : totalCoups; } 运行测试:
// 边界检查
0)); 1)); 5)); 5)); 5)); 1));
assertEquals(0, cm.getNumOfCoupsCanUse(0, 5)); assertEquals(3, cm.getNumOfCoupsCanUse(4, 5));
} } 运行结果为:
3、完成程序
public int getNumOfCoupsCanUse(int months, int totalCoups) { if (months == 1) { return totalCoups >= 1? 1:0; } else if (months == 2) { return totalCoups >= 2 ? 2 : totalCoups; } else if (months >= 3) { return totalCoups >= 3 ? 3 : totalCoups; } else { return 0; } } 运行测试:
Agent
小时候结对学习
小时候结对学习的关键词
长大了要结对编程
结对编程的关键词
结对中需要做的
结对的好处
互相学习,学习人家的设计思路、开发技巧 互相backup 提高产品质量 促进沟通 促进问题及时反馈
结对中的取舍
不是结对编程,而是结对开发 无需两两同时进行 需要根据项目的大小和难易而定
2、写一个测试程序
public class CouponManagerImplTest extends TestCase { public void testGetNumOfCoupsCanUse() { CouponManagerImpl cm = new CouponManagerImpl();
重构程序
/** * 根据选择充值月数和拥有的最大红包数,取得可用红包数 * * @param months 充值月数 * @param totalCoups 拥有的最大红包数 * @return 可用红包数 */ public int getNumOfCoupsCanUse(int months, int totalCoups) { if (months >= 1 && months <= 3) { return (totalCoups >= months) ? months : totalCoups; } else if (months == 6) { return (totalCoups >= 3) ? 3 : totalCoups; } else { return 0; } } 运行测试:
总结
孰能无过?每个人都会犯错误。不能把错误留 给测试。 编码规范、设计原则无法很好地执行。 团队成员变化较大,复杂逻辑的模块其他开发 成员很难接替。 产品质量所有人都具有重要的责任 团队成员如何在项目中互相学习?结果:
assertEquals(0, cm.getNumOfCoupsCanUse(0, 5)); assertEquals(0, cm.getNumOfCoupsCanUse(4, 5)); assertEquals(0, cm.getNumOfCoupsCanUse(7, 5));
Google 的测试文化
所有工程师对质量有着同等重要的责任 测试的任务不仅是发现bug,更重要的是帮助开 发人员一起提高产品质量 有效地进行验收测试、持续集成、测试驱动开发、 自动化测试、结对。 开发在设计的同时就考虑可测试性。 重沟通,每周会沟通做了什么功能,存在什么风 险 以任务而非角色安排工作,共享同样的目标,共 享同样的任务。
工匠师傅的“测试驱动开发”
这个就是 线
工匠一:先拉上一根水平线,砌每一块砖时,都与这根水平线进行比较,使 得每一块砖都保持水平。 工匠二:先将一排砖都砌完,然后拉上一根水平线,看看哪些砖有问题,再 进行调整。
你会选择哪种工作方法呢?
有可能你会骂工匠二笨吧!这样多浪费时间呀! 然而我们自己想想,我们平时在编写程序的时候又是怎么做的呢? 我们就是按工匠二的方法在干活的呀! 甚至有时候比工匠二还笨,是整面墙都砌完了,直接进行"集成测试",经常 让整面的墙倒塌。 看到这里,你还觉得自己的方法高明吗?
Why TDD?
确保每个方法都是可用的且已被测试过 确保及时发现出现问题的模块
添加或修改代码更容易 频繁地运行测试 迭代式递增开发 不断重构以改善设计