关于Python中的单元测试,步步惊心续集之怎样狸猫换太子?!

来源:互联网 发布:淘宝新店怎么刷信誉 编辑:程序博客网 时间:2024/04/28 22:08

最近了解了一些关于敏捷开发的思想,感觉不错,因此想借此机会尝试一下敏捷。因为刚接触Scrum,所以刚开始不准备太深入,但起码要先建立起写测试的习惯,所以准备把原先的代码都加上单元测试。做的过程中才发现,很多代码逻辑场景不知道该怎么做单元测试,现在看来,主要是是因为写的时候没有关于测试的考虑。说白了,本质就是单元测试不是万能的,不是所有代码场景都适合的,所以,敏捷中说单元测试是一道门槛,能够检验你的代码是否优良。

不得已,发QQ群,论坛发帖求助各位测试达人,这里是发帖子的网址:

http://bbs.chinaunix.net/thread-4112662-1-1.html

http://bbs.csdn.net/topics/390650692

http://bbs.chinaunix.net/thread-4112669-1-1.html

截至目前浏览量挺多的,但是却没人回答。我猜一是目前国内做这方面的的确很少,思想没转变过来;另一方面,可能因为是周末的关系。帖子先不结,看是否有意见补充。

一个敏捷QQ群里有个Agile coach(敏捷教练)出来跟我交流了一下,终于感觉有拨开云雾见月明的感觉,非常感谢他的帮助,只可惜壮士没开博客,也不愿意留名。因此,这里总结一下,欢迎交流。

顺便把原帖内容贴到这里:

-------------------------------------------- 帖子开始 --------------------------------------------------------

标题有点儿噱头,问题说白了就是下面的场景该怎么实现单元测试?

Python code
?
1
2
3
4
5
6
7
8
#人物类——若曦
class RuoXi:
    '''若曦生了一个太子'''
    def __init__(self):
        pass
    def tai_zi(self):
        print "太子"
        return "太子"

Python code
?
1
2
3
4
5
6
7
8
9
10
#场景类——皇宫
class HuangGong
    '''皇宫里的生活经常会上演步步惊心的大戏'''
    def __init__(self):
        pass
    def bu_bu_jing_xin(self):   #步步惊心
        print "《步步惊心》Action"
        xixi = RuoXi()
        child = xixi.tai_zi()
        ...


现在我们要对bu_bu_jing_xin()这场戏单元测试一下?但是实际上我们的太子还没生出来呢?肿么办?那么我们必须要Mock一个狸猫的东西来代替太子。
可惜我们没法进入皇宫呢?这又肿么办?
Python code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
#单元测试类
class HuangGongTest(MockTestCase):
    def setUp(self):
        print '各演员就位...'
        print '各导演就位...'
        print 'Action...'
        pass
 
    def tearDown(self):
        pass
 
    def test_bu_bu_jing_xin(self):
        pass #靠,演员,导演都齐了,这缺了太子啥事也干不成啊,这样耗下去损失可够大的呀....
请看官们看看这tai_zi()的问题怎么解决?

以上文字表述仅仅是想激发大家兴趣,让大家能够更容易思考,在求知的道路上也希望能给大家增加一点儿乐趣;如果不喜,可以看下面更严谨的说法:
我们要对HuangGong类中的bu_bu_jing_xin()这个方法进行单元测试,但是RuoXi对象是在此函数中生成的,而RuoXi中的tai_zi()这个函数是一种妨碍测试的资源,比如,网络请求之类的,数据库的内容之类,但是这样怎么测试呢?

三思而放水!!!

-------------------------------------------- 帖子结束 --------------------------------------------------------

根据交流记录,我总结如下几点:

1.代码要遵守单一职责的模式,数据处理和业务逻辑要尽量分开。

2.对于网络,数据,文件读写的操作一定要和业务逻辑分离开,除非你的逻辑就是以上三种。。。

3.原始数据尽量封装成业务对象,传到业务逻辑里。也就是业务逻辑尽量不要依赖原始数据。比如说一段json,你的业务逻辑如果一个参数直接是json串的话,那么你在方法内部就难免要处理json数据,对吧。这样的话,你的业务逻辑其实就包括了数据处理和业务处理。

4.如果你发现你的一个private方法需要测试,而且很那从public方法的层面对它进行测试,那么多半这个private方法应该属于一个新的,或者其他的类的public方法

5.对象的生成和使用要尽量分开,方便对象的替换,跟依赖注入比较像。对象的生成和使用都在一个逻辑里,此对象和所在逻辑的对象之间的关系属于聚合关系,正常来讲这个对象或其方法很难被mock,因此,需要替代的资源无法替换,这也是单元测试所带来的难度。一旦在一个模块中创建了另一个模块中的具体对象,依赖就产生了,给替换带来难度。贴一张代码图:



思想上已经扫除了障碍,想说的上面也都说了。至于“标准”答案,我就不说了,也没啥标准答案,领会了精神,最适合你的测试场景的就是你的答案。

如果后面帖子中有好的观点,我会继续添加到这里。

原创粉丝点击