关于TDD,一个函数如果需要网络访问怎么TDD?

tinyfool 发布于 2014年12月03日
无人欣赏。

首先把功能分成需要网络和不需要么?

然后Mock网络部分,只能测试非网络部分?

共10条回复
phaytsukiming 回复于 2014年12月03日

如果是UT的话,大致就是这样。IMHO,设计良好的代码,很容易测试,即通过可测试性来反向提升模块化。

tinyfool 回复于 2014年12月03日

@董一凡 大师来给我讲讲TDD,现在有些小疑惑

candyshop 回复于 2014年12月03日

一般单元测试的原则就是,测试SUT可控的代码,对于SUT不可控的代码进行模拟。

你这里的话,网络部分mock返回值就好。

真实的网络请求留给集成测试去做吧。

董一凡 回复于 2014年12月03日

2楼 @tinyfool TDD 粗糙点说,就是测试一个函数的输入和输出,而有网络调用的函数,网络部分的输入输出可以认为是确定的。既然确定那就是可信赖不用测了,你自然就可以 mock 所有网络部分的返回值了。这就跟你不需要测系统函数一样,因为他们是可信赖的了

当然有人会说系统函数也会出错,但是这已经超出你的控制范围了,也超出了 TDD 的范围

tinyfool 回复于 2014年12月03日

4楼 @董一凡 对,但是比如我的网络通讯是这么一句

NSData *jsonData = [NSData dataWithContentsOfURL:url];

我怎么模拟?还有比如,我的代码本来要在两次请求之间暂停3秒的,否则对方服务器会踢掉我,在测试代码里面怎么办?

tinyfool 回复于 2014年12月03日

1楼 @phaytsukiming

3楼 @candyshop

4楼 @董一凡

哪些函数应该测试?特别细小的需要测试么?比如只有1-2行,完成的功能感觉上想当然也错不了的

candyshop 回复于 2014年12月03日

5楼 @tinyfool 有时为了利于单元测试,代码是需要做些调整的。例如你的代码可以这样修改:

NSString *content = [DataEngine getContentFromURL:url];
NSData *jsonData = [content dataUsingEncoding:NSUTF8StringEncoding];

然后你可以模拟DataEngine那个方法的返回值了。

董一凡 回复于 2014年12月03日

5楼 @tinyfool 你这个例子的话,后边是系统调用,所以你只需要假设出返回值就行了,具体说就是为空和合法数据。3秒踢掉就等价于返回为空嘛。

6楼 @tinyfool 按教条来说是所有函数都要测,实际来说,就测自己觉得可疑的,

题外话,这个度的把握就和程序员的专业程度极度相关了。所以和很多人的想法相反, TDD 并不是给容易犯错的初级程序员用的,因为他们根本不知道这个度,即便你说要求100%覆盖率,因为测试时候的输入数据的选择是很有讲究的,所以很有可能是写了一堆不痛不痒无意义的测试代码。相反高级程序员就能很敏锐的识别易错函数,TDD 是为这类人准备的

candyshop 回复于 2014年12月03日

6楼 @tinyfool 一般Public的函数需要测试。

或许你会问要不要测试Priviate的函数,我的个人体验是不需要,因为你如果严格遵循的TDD的话,Private的函数都是从已经验证过的Public函数中抽取出来的。

cnsoft 回复于 2014年12月04日

8楼 @董一凡 @tinyfool 受益匪浅啊.

应该不用分成要或不要网络. 而是要 stub 一下关键的资源. 可以是个web 服务,返回指定数据啥的. 拙见见笑.

我用过 Python 可以动态替换一些函数. 就很容易做到 Mock or Stub 测试了. 不用太费力. 目标是为了组织足够的测试用例 来确保功能是ok的. 就是一组TestCase. 测试数据 是录制和抓取的样例数据 最难的是那种不可序列化的对象 or 环境依赖. 我的方法就是数据模拟. 不可能真的去建个socket啥的. 就是模拟数据.

真的实行起来, 也挺难的, 尤其是人员比较多, 测试用例经常被破坏. 如果在原有代码里插入测试代码 更混乱. 稍微进化一些的方法是: 继承一个class 覆盖实现要模拟的函数. 装配数据就好了. 或者利用语言的特性. python可以加@decorator

有个概念是 可测试代码 和 不可测试代码。 要是想支持测试, 肯定要额外调整一些代码才可以的. 而这个调整搞不好 还会带入更多bug. 极端的人也反对做调整. 但是想想, 产品真的上线以后, 每次打一个版本, 如果没有办法快速验证所有功能,是多么可怕的事。即便事后找到谁带入了新bug 也没什么意义. 该造成问题的已经造成了。

总之, 能做到TDD的 从上到下都是很认可的才行。

举个例子.

@TestWrap
def getURL( s) :
    balabala....  

def TestWrap(s):
    if testEnable:
         return  testdata.get(xxx);
    return s
登录 或者 注册