实况转播:TDD开发树类

slowgrace 2009-03-24 07:56:21
看了些关于XP的文章,很感兴趣,今天要着手重写树类了,决定试试用测试驱动开发的办法来做(TDD),因为是摸着石头过河,所以想把这个过程写下来,请各位指点。大概的形式是定期上来汇报,我做了什么测试及实现了什么功能。初步想法是每次集成完之后上来汇报一下。

说明一下啊:
(1)我是在Access的VBA下编程,所以像这个http://www.xprogramming.com/software.htm,里的许多自动化测试工具我是指不上了。
(2)我要做的是个树类,懂得自己从数据库读数据,并根据用户在树上的操作增删数据,另外还懂得一些界面操作,比如接到splitbar的消息会自动调整自己的位置等等。关于这个树类的设计讨论见这个帖子这个帖子

OK。我先去洗个头,过会儿接着来。
...全文
504 59 打赏 收藏 转发到动态 举报
写回复
用AI写文章
59 条回复
切换为时间正序
请发表友善的回复…
发表回复
slowgrace 2012-01-02
  • 打赏
  • 举报
回复
来挖坟~
xiaophi 2009-07-07
  • 打赏
  • 举报
回复
佩服楼主
slowgrace 2009-04-17
  • 打赏
  • 举报
回复
to zhao和ahao:你们俩的名字好像。

我一个叫做 z耗。另外一个念a耗。

嘿嘿。
Tiger_Zhao 2009-04-17
  • 打赏
  • 举报
回复
既然正在学习一种方法,就要认真按他的规则去做。

没有最好,只有更好。
只有你掌握的方法多了,才可以进行横向比较,才能选择一种适合自己的方法。

在学习方法阶段就进行这种讨论毫无益处,经验是要靠自己积累的,就此打住!
ahao 2009-04-17
  • 打赏
  • 举报
回复
[Quote=引用 51 楼 slowgrace 的回复:]
引用 49 楼 Tiger_Zhao 的回复:

引用 43 楼 slowgrace 的回复:
这次迭代的第二个遗留问题,和这两个集合有关。以CTreeCtl为例,它需要保留一个叫m_trd的私有成员变量指向gcolTrds的某一项么?还是只保留m_strNodeTable(节点表名),然后提供一个这样的公有属性:…

应该是m_trd,而且应该是 WithEvents 声明,否则你怎么进行多个 CTreeCtl 的同步。


我觉得我的办法更好,可是也拿不准,所以写出来请您老人家点评:)

先说说…
[/Quote]

我觉得两个方法本质上没有太大区别,你拿着m_strNodeTable,其实也是一样的耦合(稍微小点吧)。减少耦合的原则是对的,不过也要考虑到方便和效率的因素,没有耦合的类是没有用的类。
withevents不太懂,不好多说,不过耦合到全局单件类也是一个很强的耦合,因为这个类的变化是影响全局的。我担心的是这个CMsgMate类里的不相干的消息类型会不会太多,关系太松散,CMsgMate职责太多,内聚性不够。如果某些消息之间的关系不大,可以分成几组,归于不同的接口负责,把依赖某个全局单件对象变成依赖某几个接口(可以由随便什么类实现,比如CMsgMate,或者多个类去实现)。这个我只是提一下,目前这个阶段你没有必要去重构这个。

clear_zero 2009-04-16
  • 打赏
  • 举报
回复
加油,加油
lyserver 2009-04-16
  • 打赏
  • 举报
回复
我看得好辛苦,那楼主一定比俺更辛苦,佩服楼主的钻研精神,顶!
slowgrace 2009-04-16
  • 打赏
  • 举报
回复
另外,这两天看了一点《测试驱动开发》的第3部分。感觉这本书是给笨人写的,比如像我这样的,呵呵。因为他提到的那些困扰我全都有。

比如,他教你一个办法,如果写代码写到一半要离开办事去,那就留下一段铁定出错的代码在那里,办完事回来就能很快接上电了。不然回来后就得想半天,该做啥。

另外,他还做个列表,其实就是个文本文件,列出所有想到的要做的事(要写的代码),做完一条就划掉一条。这和我一样一样的啊。因为我记性超级差,所以我想到什么都记下来,然后要做事的时候就去看列表。比如,我的下一次迭代,这还完全没开始呢,都写了十几行了,一行代表一件要做的事。
slowgrace 2009-04-16
  • 打赏
  • 举报
回复
[Quote=引用 49 楼 Tiger_Zhao 的回复:]
引用 43 楼 slowgrace 的回复:
这次迭代的第二个遗留问题,和这两个集合有关。以CTreeCtl为例,它需要保留一个叫m_trd的私有成员变量指向gcolTrds的某一项么?还是只保留m_strNodeTable(节点表名),然后提供一个这样的公有属性:…

应该是m_trd,而且应该是 WithEvents 声明,否则你怎么进行多个 CTreeCtl 的同步。
[/Quote]

我觉得我的办法更好,可是也拿不准,所以写出来请您老人家点评:)

先说说消息使者类:CMsgMate。它定义了许多事件,并提供许多public函数用于raise这些事件。当我需要在2个类之间传递消息时,我就在这2个类里都加入CMsgMate类型的成员变量,并在对象实例化的时候,让这2个成员变量都指向同一个CMsgMate实例。这样1个类的CMsgMate触发事件的时候,另外一个类的CMsgMate成员也能收到。

实际上我设了一个全局的CMsgMate对象gcmm。所有需要收发消息的类都含有一个指针指向gcmm。这样它们就可以互通有无了。比如,当一个CTreeData对象的数据发生变化时,它就通过gcmm发一个消息,说自己变了。剩下的是CTreeCtl响应它还是CTreeWnd响应它就都没关系,爱咋咋,反正我发了通知了。

我觉得这样比较好,这样类和类之间耦合稍小一点,只通过一个gcmm耦合。你觉得呢?

所以,由于有gcmm的存在,我可能就不需要在CTreeCtl里维护一个CTreeData对象了?是不?
slowgrace 2009-04-16
  • 打赏
  • 举报
回复
谢谢项兄的鼓励,谢谢楼上各位的支持。谢谢zhao,关于类间消息的传递一会儿另起一帖讨论。

之前的开发日志点击这里:http://blog.csdn.net/slowgrace/archive/2009/04/12/4066283.aspx
0416 v0.06 支持层次百分比的一次性计算

一、完成的
这次迭代主要是处理节点value和percent的一次性计算。关于层次百分比的概念,请见这个链接:http://blog.csdn.net/slowgrace/archive/2009/04/16/4084636.aspx。主要的时间还是花在测试和重构,真正用于实现的时间很少。
i.测试:
1.重构
a)IteRst相关的
i.实现一个用于遍历记录集的过程IteRst()
ii.加一个类ChkRst,用于检查单个记录
iii.多挂计数的检测改用IteRst过程和ChkRst类
iv.无重名节点的检测改用IteRst过程和ChkRst类
v.确认基础节点没有子节点的检测改用IteRst过程和ChkRst类
vi.CheckDetail改用IteRst
vii.IteNodes仿照IteRst,改为直接弹出Msg
b)通过API发消息相关的
i.CTreeCtl里加tester方法,用于供外界通过类似callbyname的机制调用私有的事件过程。另外把前两天图省事变public的事件过程变回private。
ii.用API发消息做nodeExpand的检测
2.新测试:
a)随机选定节点检查
i.它自己的金额是否是孩子金额的总和
ii.孩子的百分比是否等于孩子金额除以它的金额
3.老测试rerun:
a)让checknodedata里和value percent的相关语句能正常工作
b)让CheckNode里的相关语句能检查NodeText的值和Percent
ii.实现
1.新实现:递归计算层次百分比
2.重构:检查NodeText,让它能正常显示百分比和值

二、遗留问题
(1)计算层次百分比的效率问题。现在计算2万余条纪录需要近20分钟,汗。问题我写在这个帖子里:http://topic.csdn.net/u/20090416/17/2aecf189-0d41-404d-9e21-22361c1ac62a.html
(2)通过API向控件发消息触发事件的问题。这个折腾了一、两天,只解决了一部分。没解决的主要是鼠标消息的发送,貌似作为队列消息,只能post,而post是异步的,不是我想要的效果。另开了一帖折腾这个,在这里:http://topic.csdn.net/u/20090416/15/f990c1f4-34d0-48b6-8fdf-ac3bb4836bd7.html

三、下次迭代
目标:
(1)完成百分比的动态更新,这个涉及到一系列类之间的协作,我得记着迈着小步做测试和实现,不要又像上次写树生成那样一股脑写了一堆没测试的代码。
(2)存储过程?我想看看ACCESS存储过程方面的资料,看看是否需要把这个引入到实现中,如果需要,就在这次迭代中引入。
时间:预计3天。因为功能复杂、并且设计我不熟悉的新技术。
老河流水人家 2009-04-14
  • 打赏
  • 举报
回复
p
Tiger_Zhao 2009-04-14
  • 打赏
  • 举报
回复
[Quote=引用 43 楼 slowgrace 的回复:]
这次迭代的第二个遗留问题,和这两个集合有关。以CTreeCtl为例,它需要保留一个叫m_trd的私有成员变量指向gcolTrds的某一项么?还是只保留m_strNodeTable(节点表名),然后提供一个这样的公有属性:…
[/Quote]
应该是m_trd,而且应该是 WithEvents 声明,否则你怎么进行多个 CTreeCtl 的同步。
xyjdn 2009-04-14
  • 打赏
  • 举报
回复
西西MM,给你一个建议,把你所做过的记录同类的事件把他们抽象、归类出来,抽象的级别越高,你就越接近他的本质。这样会对你的提高很有好处。
细节就帮不了你了。我算不上是一个程序员。
xyjdn 2009-04-13
  • 打赏
  • 举报
回复
楼主mm做事很入心,
会有出息的,用不了几年,it圈内又会多一个好手了
xyjdn 2009-04-13
  • 打赏
  • 举报
回复
奉命顶贴
upup
CSDNATM 2009-04-13
  • 打赏
  • 举报
回复
good
slowgrace 2009-04-13
  • 打赏
  • 举报
回复
现有的几个类的小结

(1)CDetailList,缩写dlst
一个CDetailList对象对应一个细节表。它包含一个NODE_DETAIL类型的数组,每一个NODE_DETAIL结构对应一条细节记录。CDetailList对象初始化时会加载相应的细节表的所有数据。

(2)CTreeData,缩写trd
一个CTreeData对象对应一个节点表。它包含一个CNodeData对象的集合。CTreeData对象初始化时会加载相应的节点表的所有数据。

(3)CNodeData,缩写cnd
一个CNodeData对象对应一条节点记录。

(4)CTreeCtl,缩写trc
一个CTreeCtl对象对应一个treeview控件。它知道自己是属于哪个树窗,也知道自己表现的是哪个节点表的数据。

(5)CTreeWnd,缩写twd
一个CTreeWnd对象对应一个树窗。所谓树窗,是指含有树控件的窗体。它含有用于显示细节的子窗体和listview,它懂得在树控件上的当前节点发生变化时,相应地调整自己的显示。它还负责一些罗嗦的初始化工作,像放置控件的位置、设置imagelist、设置event procedure、设置快捷菜单等。

全局有个两个集合变量,一个是CDetailList的集合gcolDlsts,一个是CTreeData的集合gcolTrds。这也就是zhao一直以来所建议的“把数据放在内存里”的具体实现。大家要用数据的时候都去访问这两个集合。

这次迭代的第二个遗留问题,和这两个集合有关。以CTreeCtl为例,它需要保留一个叫m_trd的私有成员变量指向gcolTrds的某一项么?还是只保留m_strNodeTable(节点表名),然后提供一个这样的公有属性:
public property get Trd() as CTreeData
set Trd = gcolTrds(strNodeTable)
end property

这两种的区别在于,第一种中,公有的那个CTreeData变量的引用计数恒久地增加了,直增加到CTreeCtl对象消亡为止。第二种中,只有在调用Trd属性的时候,会临时性地增加CTreeData变量的引用计数。

我隐约地觉得,也许,如果我不需要对m_trd提供with events的话,我就不需要用第一种。而实际上我还真不需要对m_trd提供with events,因为我有专门用于发送消息的CMsgMate类。

对了,忘了说,除了上面的几个主要的类外,还有如下辅助类和模块:
(1)CMsgMate:用于发送自定义消息
(2)CTabStrip
(3)ChkCnd:这是一个测试类,专用于测试node相关数据的。
(4)basTree:树相关的全局函数。前面那两个集合变量,还有一些常数都在这里。
(5)basTest:测试相关的。生成随机数的一系列函数等。
(6)basAPI:API相关的一些声明。
slowgrace 2009-04-13
  • 打赏
  • 举报
回复
之前的开发日志点击这里:http://blog.csdn.net/slowgrace/archive/2009/04/12/4066283.aspx
0413 v0.05 支持树节点展开expand

这次迭代用了小1天,核心功能(expand)大约只用了20分钟。很多时间是在写测试,还有对类进行重构。做了如下工作:

i.测试相关的
1.改进测试:把见光标志位的测试改为根据真正的逻辑判断而不是确认只展开头3层
a)剥离generation检测;
b)如果孩子没有见过光,那么确认打开后,孩子见光,孙子没见光。
2.改进测试:把测试树生成的功能和测试子窗体listview显示的功能分到两个测试窗体中
3.改进测试:把load数据和生成数据的测试分别剥离出来
4.增加tag检测:确认同一节点的所有孩子的见光标识位一致
5.增加同名树检测
6.重新测试listview,把click事件和expand事件之间的逻辑放进测试代码里
ii.实现相关的
1.改进addchildtree:如果当前father节点已存在,就只添加子节点。用于expand
2.重构CTreeWnd:让它维护CTreeCtl数组
3.重构CTreeCtl:使它维护imagelist,这样就不用每次手工设置imagelist了
4.处理数据的集中加载和卸载
a)添加用于数据卸载的快捷菜单,在CTreeWnd里定义一次就好
b)把new CTeedata 改成GetTrd
c)修改函数loadDetails,防止重复load

心得:倒着写。所谓测试先行,就是倒着写。先写最后的调用而已。这次迭代有很多的重构(把以前写的一些代码作废掉,用更好的设计取代),每次重构的时候我都会忍不住直接去写实现代码,要提醒一下自己才先去写最后的调用。那就是这个小时你要完成的代码的奋斗目标,很明确地放在那儿,首先让你的调用能通过编译,其次让你的测试能顺利执行到最后一个语句,而不是停在某个assert语句。这种开发习惯对我这样的注意力超级不集中的菜鸟还是很有帮助的。我准备把这个习惯坚持下去。

遗留问题:本次迭代有两个遗留问题。
(1)API发消息的问题。我是那种一旦起了心思就会一直惦记下去的。所以,虽然测试expand,可以通过把expand事件过程设为public,然后直接调用那样测。可我还是不死心,想用API发消息来做。这也是导致这个20分钟可以完成实现的迭代拖了这么久的原因之一。这个问题我写在这里,http://topic.csdn.net/u/20090412/21/5cc102c6-f281-4870-a7d6-3755f785c715.html,各位帮看看是哪里不对好么?(一会儿我会再起一楼交待现在有的这些类。)
(2)类的设计。这个一会儿在楼下交待完各类再详述。

(另,在抿红酒,有点晕了,没有小马的酒量,呵呵)

下一个迭代,支持层次百分比功能,时间预期,1天。
slowgrace 2009-04-12
  • 打赏
  • 举报
回复
之前的开发日志点击这里:http://blog.csdn.net/slowgrace/archive/2009/04/12/4066283.aspx
0412 v0.04 支持树节点点击,listview同步显示

这次迭代的工作主要在CTreeWnd类完成,加了两个私有函数用于listview的充填,然后在CTreeWnd类的m_cmm_SelChanged事件过程里调用这个函数。因为框架在上次迭代里已经搭好了,写起来很轻松不费脑子。另外,我对CTreeWnd类做了重构,加了一个imagelist成员变量,这样以后就不用手工设置listview的icons了。

对于测试,我现在这么做。每次我要实现什么新功能的时候,我都问问自己:
(1)这个功能之后会否有别的实现?如果有,也许我就应该写个测试,以免下次重构的时候我还的费脑筋想怎么测试;
(2)这个功能的测试是否很简单,是否打眼一望就知道了?如果是,那我就不需要写测试。比如我这次迭代加了个小功能,让listview在充填内容后自动调整列宽,我就没写测试,只是在测试程序的末尾来了个msgbox,提醒程序员目测一下列宽是否正确,呵呵。我不知道遇到这种情况,kent back他们会否写。

下一个迭代,我要完成treeview的expand事件的处理。就是在expand事件发生时,要生成新的节点,if necessary.
嗷嗷叫的老马 2009-04-09
  • 打赏
  • 举报
回复
顶顶MM!!!
加载更多回复(39)

1,265

社区成员

发帖
与我相关
我的任务
社区描述
软件工程/管理 管理版
社区管理员
  • 研发管理社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧