`

TDD step by step

 
阅读更多
   什么是TDD,字面很好理解,曾经的我以为就是先写测试,然后写实现,接着跑测试,通过,收工。今天厚着脸皮抓到高级敏捷咨询师力岩同学一起Pair,告诉我什么是真正的TDD,他以一个小Case的练习把我带进了TDD的大门,下面就来总结一下他是怎么step by step TDD的。
    需求:国际象棋,有一个车(Rook),一个国王(King),当国王和车处于一条横线或一条竖线的时候,就叫做将军(checkmate),现在就根据TDD来实现这个Story。

1、创建测试用例,
    @Test
    //注1:方法命名一定要清楚,代码即文档
    public void should_rook_checkmates_king_when_rook_and_king_in_the_same_line() throws Exception {
        //注2:完全按照自己的想法来写,比方说这儿,我们需要一个rook和一个king,并且要放到一个棋盘上才能判断是否将军,是吧?
        ChessBoard chessboard = new ChessBoard();
        King king = new King();
        Rook rook = new Rook();
        
        chessboard.addKing(king,3,4);
        chessboard.addRook(rook,4,4);
        
        assertThat(rook.isCheckmate(),is(true));
    }
当然此时的代码肯定会有编译错误,这时,我们可以通过IDE的fix功能让编译通过先,记住,只是让编译通过,不要去想新加的类啊,方法的测试,设计什么的。不要偏离主航道,切记。

2、运行测试用例。经过step 1之后,我们会得到几个对象,和一些dummy的方法,因为是dummy的,很明显会报各种错误,NullPointer啊什么的。

3、以最简单的方法让测试通过,不要去考虑具体的实现逻辑实现,代码美观这些问题,专注于一个点,让测试通过,以我们这个测试为例,我们直接让rook的isCheckmate方法返回true就行了。

4、补测试用例,很明显,我们前面的方法很容易就绕过了测试的保护,说明我们的测试用例覆盖不够。接下来,加一个测试用例覆盖没有将军的情况
    @Test
    public void should_not_rook_checkmates_king_when_rook_and_king_is_not_in_the_same_line() {
        ChessBoard chessboard = new ChessBoard();
        King king = new King();
        Rook rook = new Rook();

        chessboard.addKing(king,3,3);
        chessboard.addRook(rook,4,4);

        assertThat(rook.isCheckmate(),is(false));
    }


5、重跑所有测试用例,新补的这个测试用例不能通过。

6、修复失败的测试用例,专注于修复失败用例,怎么简单怎么来,这个Story下我们就需要修改rook的isCheckmate()方法。跟step 1一样,用最简单的方法使编译通过,这时的Rook类代码如下
public class Rook {
    private King king;
    private int x;
    private int y;

    public boolean isCheckmate() {
        //注1:要判读是否将军,必须先知道King的位置吧
        int king_x = getKing().getX();
        int king_y = getKing().getY();
        //注2:横坐标或者纵坐标相同,则将军
        if(x == king_x || y==king_y){
            return true;
        }
        return false;
    }

    public King getKing() {
        return king;
    }
}
同时,King类中也新增了2个dummy方法getX(),getY().

7、重跑所有测试,测试仍然不通过,继续fix测试,进过一系列的修改让测试通过,Rook的代码编程这样了
public class Rook {
    private King king;
    private int x;
    private int y;
    private ChessBoard chessboard;

    public boolean isCheckmate() {
        //注1:要判读是否将军,必须先知道King的位置吧
        int king_x = getKing().getX();
        int king_y = getKing().getY();
        //注2:横坐标或者纵坐标相同,则将军
        if (x == king_x || y == king_y) {
            return true;
        }
        return false;
    }

    public King getKing() {
        //注3:这个king的应该是从一个棋盘上扣下来的才有意义
        return chessboard.getKing();
    }

    //注4:chessboard从哪儿来,给个setter让外部能传入,什么时候设呢?把rook放到棋盘的时候
    public void setChessboard(ChessBoard chessboard) {
        this.chessboard = chessboard;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }
}
还有其他很多修改就不一一列出。

8、所有代码逻辑完成,测试通过,接下来就是Bad Smell的清理,以Rook类为例,很明显可以看出的Bad Smell 有一下几点
public class Rook {
    //smell 1:删除无用变量
    private King king;
    //smell 2: x,y强耦合,可以内聚成一个变量
    private int x;
    private int y;
    private ChessBoard chessboard;

    public boolean isCheckmate() {
        int king_x = getKing().getX();
        int king_y = getKing().getY();
        //smell 3:if条件的含义不明,可以抽出方法
        //smell 4: 整个if语句可以inline成一个语句
        if (x == king_x || y == king_y) {
            return true;
        }
        return false;
    }.....
记住每清理一个Bad Smell就运行一下测试,小步快跑,避免breakdown测试。

9、展示一下最后完成的Rook类
public class Rook {
    private ChessBoard chessboard;
    private ChessBoardPoint position;

    public boolean isCheckmate() {
        return isRookCheckmate();
    }

    private boolean isRookCheckmate() {
        return position.getX() == getKing().getPosition().getX() || position.getY() == getKing().getPosition().getY();
    }

    public King getKing() {
        return chessboard.getKing();
    }

    public void setChessboard(ChessBoard chessboard) {
        this.chessboard = chessboard;
    }

    public void setChessboardPosition(ChessBoardPoint chessBoardPoint) {
        this.position = chessBoardPoint;
    }
}
当然这不是终点,只是起点,可能还有很多bad smell,这整个的TDD的过程中,看着代码一步一步的变优美是一个非常享受的过程。


总结: 今天的Pair,感受最深的是,专注,思想永远在一条线上,不要过多的去考虑当前不涉及的东西。
分享到:
评论

相关推荐

    TDD-Softeam:进行Softeam TDD培训的练习,并提供逐步解决方案

    描述中的“TDD step by step - Roman to arabic converter.odp”揭示了这个培训课程的一个具体示例,即如何使用TDD方法来实现一个罗马数字到阿拉伯数字的转换器。这个".odp"文件是一个OpenDocument Presentation,...

    Visal C# 2010 step by step (英文)

    《Visual C# 2010 Step by Step》是一本由John Sharp编写的书籍,旨在帮助读者逐步掌握Visual C# 2010编程语言及其相关技术。本书适合初学者和有一定编程基础的学习者使用,通过实践案例深入浅出地介绍了C#的基本...

    Microsoft ASP.NET_3.5Step by Step

    《Microsoft ASP.NET 3.5 Step by Step》是微软出版的一本关于ASP.NET 3.5技术的详细教程,旨在帮助读者深入理解并掌握这一强大的Web应用程序开发框架。ASP.NET 3.5是.NET Framework 3.5的一部分,它极大地扩展了...

    tdd-by-exemple

    记住TDD算法 快速添加测试 运行所有测试并看到新的测试失败 做一点改变 运行所有测试并看到它们都成功 重构以消除重复 ##第 I 部分:金钱示例 ###金钱示例 ####分支名称:money-step1 ####分支名称:money-step1-...

    kata-tdd-1-THANHNGUYEN:TDD Kata 1 by Thanh Nguyen

    kata-tdd-1-THANHNGUYEN 卡塔二手包咕噜声Grunt 贡献连接Grunt 贡献观看Grunt 贡献 jshint ##目录结构 app|- assets|- scripts|- app.js|- libs|- jquery-2.1.3.min.js|- style|- normalize.css|- style.css|- index...

    How+to+Use+Ceedling+for+Embedded+Test-Driven+Development.pdf

    This guide contains step-by-step examples to get you started test driving in C, especially for embedded software applications. We'll look at how to use the unit test framework called Ceedling to help...

    Test-.Driven.Python.Development.1783987928

    Go from a unit testing beginner to a master through a series of step-by-step tutorials that are easy to follow Who This Book Is For This book is intended for Python developers who want to use the ...

    Agile Swift(Apress,2016)

    This short step by step guide walks you through unit testing, mocking and continuous integration and how to get these key ingredients running in your Swift projects. This book also looks at how to ...

    ASP.NET MVC 4 高级编程 源码

    Featuring step-by-step guidance and lots of code samples, this guide gets you started and moves all the way to advanced topics, using plenty of examples. Designed to give experienced .NET and ASP...

    毕业论文中英对照翻译

    2. Step 2 – The Request is Received by the ASP.NET Pipeline 当用户在浏览器中输入 URL 并按下回车键时,请求被发送到 Web 服务器。在 ASP.NET 中,请求通过一系列模块(HttpModules)和处理程序(HttpHandlers...

    Writing.An.Interpreter.In.Go.epub

    Step by step. From tokens to output. All code shown and included. Fully tested. Buy this book to learn - How to build an interpreter for a C-like programming language from scratch - What a lexer, a ...

    Learning ASP.NET Core MVC Programming

    "Learning ASP.NET Core MVC Programming" English | ISBN: 1786463830 | 2016 | ...Explore new configuration and deployment scenarios—step by step guide to deploying ASP.NET Core web application in Linux

    Test-Drive ASP.NET MVC

    From building your first page, to data access, to integrating with web services such as Blogger.com, Test-Drive ASP.NET MVC guides you step by step. You’ll come away with a complete understanding of...

    Test-Driven+Development+By+Example-测试驱动开发【高清+有目录+可搜索+可编辑】

    1.敏捷开发强调测试先行,因为先编写测试代码,就可以有目的的预防某些bug的产生,要知道,治病不如预防!!!所以我个人觉得这个还是比较重要的,文件也不大,只有8M,但是高清。 2.本版本与网上其他资源不同之处...

    敏捷开发资料合集

    3. "Agile--Implementing SAP step by step.pdf":对于大型企业级应用,如SAP系统,敏捷方法同样适用。这本书可能会介绍如何将敏捷原则应用于SAP项目的实施,如何处理复杂的业务流程和集成挑战,以及如何确保在敏捷...

    在Perl模块上逐步创建带有测试和git的教程:从底层进行Perl模块开发,并逐步进行测试过程和git集成

    在“step-by-step-tutorial-on-perl-module-creation-with-tests-and-git-master”这个文件列表中,我们可以期待找到一个详细的教程,包含了创建Perl模块的步骤、如何编写测试以及如何使用Git进行版本控制。...

    shop:使用Ruby On Rails购买回购

    在Rails中,可以使用`step_by_step`库或者自定义状态机来管理这个流程。每个步骤对应一个控制器的action,用户在每个阶段的数据保存到session或数据库中,直到最后生成订单。 5. **支付集成**: 结算过程中往往...

Global site tag (gtag.js) - Google Analytics