• 测试驱动开发实践


    总是以为自己了解了测试驱动开发,其实做起来和了解根本不是一回事。原来觉得代码清晰得很,后来试验了一下才知道那是自己的错觉。这次,让我们抛却Eclipse的自动补全功能,来一场真正的测试驱动开发吧。

    项目描述:这是一个很简单的项目,目标是扫描磁盘上所有特定格式的文件,将其路径存储下来,通过程序可以快捷搜索到文件路径并自动定位到该文件。

    用户故事(简单点写了):

    1、              扫描磁盘,将目录下的所有文件列出来,将特定格式的文件信息存储到磁盘。

    2、              所有文件的信息可以被查询。

    3、              被查询出的信息可以双击打开所在文件夹并定位该文件。

    好了,这就是第一次的迭代目标,其中文件的格式枚举,存储到磁盘的形式,都可以以后再说,那么针对于故事的过程,我们开始设计并写测试吧:

    设计:

    1、          平面文件存储,每个文件以行为单位存储,不同属性以###分割,实例化到FileInfo类(故事1)。

    2、          平面文件叫fileDB。文件以行读取到List,以带格式的String写入(故事1)。

    3、          特定文件格式以正则表达式匹配(故事1)。

    4、          查询的条件是文件名,通过遍历List查找属性是否符合contains规则(故事2)。

    5、          用JNI explorer打开并定位文件(故事3)。

    建立测试:

    这里首先关注的是设计中的第一条。

    新建一个Junit Test Case,我将测试的类叫FileInfo,所以这个测试类叫FileInfoTest,它与FileInfo在同一包路径下,但是在不同的resource folder下。

    这个Test Case应该不能通过测试。

    事实证明,它的确无法通过测试

    然后,它应该这样被初始化。

    编译错误!那当然,因为类FileInfo还不存在,让我们建立它。

    编译通过了,我们需要它将字段输出成一个带###分隔符的字符串,字符串的组成是FileName###FileDir###FilePath###LastUpdate。

    那么测试应该变成这样了:

    为了解决这些红杠,FileInfo得变成这样。

    (这里有那么一点点牵强,就是get方法和成员变量的来源不是“刚刚好通过测试”,而是测试原本是为了引出成员变量)

    现在toString应该变成这样:a.txt###c:\###c:\a.txt###2016-01-01。

    所以测试应该变成这样(这样写代码好费时间!但参与设计的过程也相应变多,思考和工作量都在增长)

    当然,测试失败了,二者并不相等

     

    原因当然在toString

    修改FileInfo的toString方法:

    测试通过了!

    此时,我在想,如果因为某种原因,我想将###换成@@@,那么toString方法中###应该以变量的形式出现。但因为此次将修改的代码对通过测试没有任何意义,也不能增加功能,所以我不这么做。我会在什么时候这样做呢?我会等到代码的功能很多,我重构它并能展示此时测试对我重构的意义的时候。

    现在我们完成了设计1,来开始设计2吧。

    将fileDB.txt建立在项目根路径下,为了便于之后的测试,写入如下内容:fileName###fileDir###filePath###lastUpdate。

    然后新建一个测试类,用于测试还没有建立的类是否能读取fileDB并且按行存储到List。

    那么测试类应该是这个样子:

    让它通过编译。必要时,甚至可以遵从Eclipse建议的做法。

    执行测试,报错。

    List.get(0)的问题,list是空的,那么,让我们放点东西进去。

    这算什么!这不就是骗人的吗?但是我刚好通过了测试的问题,现在进入测试的下一个问题。

     

    现在是将fileDB.txt读取,并放入数据的时候了。但此时我们好像需要额外的几个方法。

    好像闻到了代码的异味,但是测试通过了。很可惜,我不知道这种情况应该怎么处理,所以我决定改变测试以来改变代码!

    好了,让我们再次恰恰好通过测试吧。另外,我们可能还需要readFileToList和getFileList的测试。刚刚我们好像忘记了,如果测试类调用了某个实例的方法,我们应该首先对实例的方法进行测试编码。

    怎么办怎么办?我没法解释这个私有方法的由来,这是我重构本能决定的,和测试没有任何关系。这里应该是我对TDD理解不深的地方。

    测试通过了。我能料到以后如果getFileInfoByLine的规则变化的话,这个私有方法还没有被测试覆盖,是一个隐患,但是现在该怎么办呢?因为它是私有的,甚至无法被其他类调用。

    好吧,既然它是私有的,那么暂时就只保证所有调用它的方法测试通过吧。

    就此,我们完成了第二个设计。这时候我发现一个严重的问题,就是我的设计没有覆盖用户故事中的对磁盘的扫描。

    目前为止,这个不严谨的实践也告诉我们,如果对TDD和敏捷理解不深,随时会似是而非最终偏离航道的。

    (未完……)

  • 相关阅读:
    高低 接口
    算法
    一致连续性定理
    Brouwer fixed-point theorem
    minimum viable product
    Python星号*与**用法分析 What does ** (double star/asterisk) and * (star/asterisk) do for parameters? 必选参数 默认参数 可变参数 关键字参数
    zabbix 添加主机接口
    zabbix 添加主机接口
    zabbix 添加主机成功失败判断
    zabbix 添加主机成功失败判断
  • 原文地址:https://www.cnblogs.com/wang-ze/p/5671879.html
Copyright © 2020-2023  润新知