`
airu
  • 浏览: 267406 次
  • 性别: Icon_minigender_1
  • 来自: 云南
社区版块
存档分类
最新评论

TDD 学习笔记(一)

 
阅读更多
以前看过《TDD by example》,现在基本都忘记光了,大致记得一切从测试开始,然后不断重构,最后不断的迭代就能得到一个优雅简洁的设计。
关于TDD的很多讨论,我这里就不说了。对于写了那么多年代码的人来说,要想转变观念,还是需要更加冷静,多思考。
TDD 中 kent Beck大师教给我们的是一门内功心法,交给我们的是如何把预想的结果转化为设计。

TDD = Test-Driven Development
很多人以为是讲测试的,其实醉翁之意不在测试,而是开发,如何使代码clean
"TDD by example”这本书的风格我很喜欢,直接从例子开始,让然一看就被吸引住。
书中的例子是一个 货币统计的例子。需要有不同的货币,相加等等。
这时,大家肯定就有一个大概在脑子中浮现。然后很快变开始写代码了。
别急,测试驱动开发中,最重要的就是测试清单了。
测试清单,可以说是半需求吧,我们写一个测试清单,这样,我们要做的事情的目的就有了。
Kent Beck建议我们把清单写出来,然后一个一个考虑。这就是to-do lists
引用

5美元 * 2 = 10 美元
5美元 等于 5美元


单完成一件事,就用横线划掉。

假设上面的清单,第一项,使用测试的风格写出来吧。
@Test public void testTimes(){
 Dollar five = new Dollar(5);
 five.times(2);
 assertEquals(five.amount,10);
}


这个测试显然通不过,因为很多东西都没有,比如Dollar类,times方法
于是我们一一建立起来。直到没有编译错误。

public class Dollar{
public amount;
public Dollar(int amount){
this.amount=amount;
}
public void times(int multipler){
  amount*=multipler;
}


上面的代码不是书中第一步的代码,但是我还是走了这么一大步。所以,这里的问题是,如何衡量每一步我们做的改动。在一个实际的或者很复杂的系统中,我们一般是不可能一步到位的,这也是为什么需要测试驱动开发的一个原因吧。但是这里,我真的觉得自己能写到这里。
我还是shamelessly的表现自己很聪明吧。
OK,一切顺利。

接下来我们看看是否可以重构,消除重复,这里我觉得差不多了。那就多些测试吧。
@Test public void testTimes(){
 Dollar five = new Dollar(5);
 five.times(2);
 assertEquals(five.amount,10);
 five.times(3);
 assertEquals(five.amount,15);
}


这个测试,连续乘,看看是不是会有意想不到的结果呢?实际上,这种测试是常见的边效应测试(side-effect)。
很好,一切与测试驱动开发的教条很符合,我们找到一个缺陷,并编写测试代码使之不通过测试。接下来我们改做些小改动。这里很明显,我们希望美元是一种独立的数字,也就是说它是不可变的。你不可能把币值为5美元变成15美元吧。那么我们在times的时候,就需要重新生产出来一张新的币值为15的美元(可以理解为电子货币,或者支票)。
好吧,先改动测试。

@Test public void testTimes(){
 Dollar five = new Dollar(5);
 Dollar tenDollar = five.times(2);
 assertEquals(tenDollar.amount,10);
 Dollar fifteenDollar = five.times(3);
 assertEquals(fifteenDollar.amount,15);
}


这时你发现,times返回值是void的,我们修改。
public class Dollar{
public amount;
public Dollar(int amount){
this.amount=amount;
}
public Dollar times(int multipler){
   return new Dollar(amount*multipler);
}
}

这下测试通过。然后来看看,我们有没有什么重复的需要重构的。很多时候,我们可能这样写times方法
public Dollar times(int multipler){
   int new_amount = amount*multipler);
   return new Dollar(new_amount);
}

如果这样的话,我们就可以使用重构中的Inline Method消除这个临时变量。得到之前我们写的times方法。这就是消除重复。
好了,我们终于划掉清单中的第一项了,接下来看第二项:
5美元 确实 应该等于5美元。那就测试测试:

@Test public void testEqualitiy(){
    assertTrue((new Dollar(5)).equals((new Dollar(5))));
}

很遗憾,我们失败了。实际上这比较的是两张5美元,虽然币值一样,但是他们确实不同。这不符合我们的意图。于是想起来了,java中需要重写equals方法。但是我们记不清了,重写equals方法有一些需要注意的。所以这里,我先做小的改动,以通过测试。
public class Dollar{
public amount;
public Dollar(int amount){
this.amount=amount;
}
public Dollar times(int multipler){
   return new Dollar(amount*multipler);
}
/*
 *I recommand you add @Override if you can't
 *remember the method clearly 
 */
@Override
public boolean equals(Object obj){
 return true;
}
}

这里直接返回ture了。肯定很多人要说了,这肯定是有问题嘛。的确如此,但是别急,我没有你那么有经验,问题只能通过测试来反映。测试通过了。看,没问题吧。哈哈。
书中提到一种triangulation。也就是对一个一眼不能看出的问题,可以使用这种方法。
1,找到一种导致测试失败的用例
2,使用stub来实现,也就是一个占位操作,直接返回或是常量。使测试通过。
3,重复1,但是这次可以用真正的写实现代码。似的通过测试。

这里,我们是在3,重复1,找到一个导致这儿假实现的失败。很容易。我们马上就找到了。
@Test public void testEqualitiy(){
    assertTrue((new Dollar(5)).equals((new Dollar(5))));
    assertFalse((new Dollar(5)).equals((new Dollar(7))));
}


这下,我们不能使用stub来实现了,只能硬着头皮写代码吧。
@Override
public boolean equals(Object obj){
 return this.amount == ((Dollar)obj).amount;
}


测试,通过。很好。第二项也就完了,划掉。不过。一切还远远没有结束。
我们考虑下,amount是公有的,这一点看着很不爽,不符合OO的封装性。
测试代码也很乱,很多重复,由于相等性已经测试完成,我们可以重构下测试代码。
再次使用Inline Method方法,重构如下:
@Test public void testTimes(){
 Dollar five = new Dollar(5);
 assertEquals(five.times(2),new Dollar(10));
 assertEquals(five.times(3),new Dollar(15));
}

清爽多了。接下来,把amount私有化改造添加的to-do lists吧。
还有,另外一种货币,Franc来了。我们也也对他像dollar一样测试。

这里,对amount的私有化,似乎很简单了,因为,由于我们在testTimes方法中,使用了对象的比较。所以,当我们修改amount作为私有的时候,似乎一切都没问题了。
0
0
分享到:
评论

相关推荐

    Study__TDD:个人TDD学习资料库

    埃迪的TDD学习笔记 :police_car_light: 警告不要合并任何PR。 :memo: 内容所有摘要都放在“问题”选项卡中。 当前,列出了以下内容: NHN FE개발랩摘要-Finsihed 견고한JS소프트웨어만들기-进行中测试Vue.js应用程序...

    AppFuse学习笔记(J2EE入门级框架)

    Appfuse是Matt Raible 开发的一个指导性的入门级J2EE框架,它对如何集成流行的Spring、Hibernate、iBatis、Struts、xDcolet、Junit、Taperstry、JSF等基础框架给出了示范。在持久层,AppFuse采用了Hibernate O/R映射...

    appfuse 学习笔记

    采用TDD的开发方式,使用JUnit测试各层,甚至测试 jsp 输出的 w/o 错误。为了简化开发,预定义好了一套目录结构、基类、用来创建数据库、配置Tomcat、测试部署应用的 Ant 任务,帮助快速自动生成源程序和自动维护...

    tdd-rails-pluralsight:使用RSpec,Capybara和Cucumber以及Pluralsight课程学习Rails的TDD

    具有RSpec,Capybara和Cucumber的测试驱动Rails 我在TDD Rails上的Pluralsight 课程中的笔记。 常用命令命令描述bin/rails s 启动Rails服务器bin/rails c 启动Rails控制台bundle exec rake routes 列出所有路线bin/...

    ng-tdd:了解AngularJS测试驱动开发

    ng-tdd 通过本书学习 它是如何工作的? 安装依赖项 npm install bower install 使用业力运行规格测试 karma start karma.conf.js 使用量角器运行e2e测试 http-server -p 5555 protractor conf.js 我的笔记 第二...

    java银行笔试题-tdd-bank-account-java:TD-银行账户-java

    中要学习/练习的两个关键事项: 测试驱动开发 结对编程 指示 使用以下命令克隆存储库。 git clone https://github.com/xp-dojo/tdd-bank-account-java 如果您遇到 SSL 问题,可以尝试以下操作。 git clone -c ...

    云学习:我对云的个人笔记和笔记

    我的云学习这是一个回购记录,用于跟踪我在软件开发(尤其是云计算)方面学到的东西。目的我决定这样做是为了让自己有更新的地方,以防万一我忘记了自己学到的东西。 另外,我决定将它公开给其他人学习,使用和重用...

    shadow:一个可常用PHP公共资源包,同时也是百度文库课程《如何写好一个PHP的类》的

    课程的主要内容可以在“课程笔记”中找到,里面有每一节的主要内容讲解。 课程介绍 首先,这门课面向PHP开发者,主要讲解一个类库的建立,开发和使用。的是,这里面讲到的都是偏实用的东西。这里面会涉及到一些经常...

    AgileJavaNote:在学习敏捷Java时记录我的笔记

    AgileJavaNote ###简介: 自学敏捷开发的思想,采用TDD 的方式开发一个学生信息系统 ###成果: 运用了UML 进行类的设计;对JAVA 中大部分的概念和特性动手编程实践;使用JUnit 对每个模块编写测试用例

    jungle-rails:用Rails 4.2构建的一个小型电子商务应用程序,用于通过示例学习Rails的目的

    由于这个项目,我了解了有关Ruby on Rails,模型-视图-控制器范例,嵌入式Ruby和测试(TDD和BDD)的更多信息。笔记: 已知问题:来宾(未经身份验证)用户仍然可以下订单。 下一步,应禁用此选项。主页管理员类别...

    模块化C代码与UML对象模型之间的映射(一)

    日子一天天过去,业余时间不多,为了避免生活华而不实,碌碌无为,我计划抽空把工作和学习中散落在笔记本和书本某些角落的总结整理出来,放到博客上备忘,同时也希望有机会和技术圈的朋友交流,增长自己的见识,我的...

    spa-tuts:学习如何使用 Tuts Plus 从头开始​​构建 JavaScript SPA

    (#mustachehttpsgithubcomjanlmustachejs) 把这一切捆绑在一起部署 锅铲Tuts Plus 课程构建 JavaScript Webapps 的笔记和项目我们将构建一个天气应用程序,作为单页应用程序。 项目分析首先模拟一些屏幕和交互。 ...

    kharioki:我的个人资料

    我是一名软件工程师,数字Nomad者,制造商,UXer和时装模特。 我喜欢DIY的东西,喜欢NCIS系列和冰镇啤酒 :beer_mug: 。 我的工具 :wrench: :hammer: :nut_and_bolt: 语言Javascript / Typescript,Python,Dart ...

    rspec-webservice_matchers:黑匣子网络应用程序测试

    RSpec :: WebserviceMatchers 一个黑盒测试Web服务器配置。 例如,是否正确配置了站点的SSL证书且未过期: expect ( 'github.com' ) . to have_a_valid_cert 这是用于进行测试驱动的Devops的工具(我刚刚完成了此...

Global site tag (gtag.js) - Google Analytics