开始测试:
Shell
; html-script: false ](test)jhaddad@jons-mac-pro ~VIRTUAL_ENV/src$ nosetests F ====================================================================== FAIL: test_blah (test_nose_example.ExampleTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/jhaddad/.virtualenvs/test/src/test_nose_example.py", line 11, in test_blah self.assertTrue(self.blah) AssertionError: False is not true ---------------------------------------------------------------------- Ran 1 test in 0.003s FAILED (failures=1) |
卓越的Mock库包含在Python 3 中,但是如果你在使用Python 2,可以使用pypi来获取。这个测试将进行一个远程调用,但是这次调用将耗时10s。这个例子显然是人为捏造的。我们使用mock来返回样本数据而不是真正的进行调用。
Python
; html-script: false ]import mock from mock import patch from time import sleep class Sweetness(object): def slow_remote_call(self): sleep(10) return "some_data" # lets pretend we get this back from our remote api call def test_long_call(): s = Sweetness() result = s.slow_remote_call() assert result == "some_data" |
当然,我们的测试需要很长的时间。
Shell
; html-script: false ](test)jhaddad@jons-mac-pro ~VIRTUAL_ENV/src$ nosetests test_mock.py Ran 1 test in 10.001s OK |
太慢了!因此我们会问自己,我们在测试什么?我们需要测试远程调用是否有用,还是我们要测试当我们获得数据后要做什么?大多数情况下是后者。让我们摆脱这个愚蠢的远程调用吧:
Python
; html-script: false ]import mock from mock import patch from time import sleep class Sweetness(object): def slow_remote_call(self): sleep(10) return "some_data" # lets pretend we get this back from our remote api call def test_long_call(): s = Sweetness() with patch.object(s, "slow_remote_call", return_value="some_data"): result = s.slow_remote_call() assert result == "some_data" |
好吧,让我们再试一次:
Shell
; html-script: false ](test)jhaddad@jons-mac-pro ~VIRTUAL_ENV/src$ nosetests test_mock.py . ---------------------------------------------------------------------- Ran 1 test in 0.001s OK |
好多了。记住,这个例子进行了荒唐的简化。就我个人来讲,我仅仅会忽略从远程系统的调用,而不是我的数据库调用。
nose-progressive是一个很好的模块,它可以改善nose的输出,让错误在发生时就显示出来,而不是留到最后。如果你的测试需要花费一定的时间,那么这是件好事。
pip install nose-progressive 并且在你的nosetests中添加--with-progressive
调试
iPDB是一个极好的工具,我已经用它查出了很多匪夷所思的bug。pip install ipdb 安装该工具,然后在你的代码中import ipdb; ipdb.set_trace(),然后你会在你的程序运行时,获得一个很好的交互式提示。它每次执行程序的一行并且检查变量。
腾讯在职8年Python开发经验的程序员写给初学者的总结,希望有用
python内置了一个很好的追踪模块,帮助我搞清楚发生了什么。这里有一个没什么用的python程序:
Python
; html-script: false ]a = 1 b = 2 a = b |
这里是对这个程序的追踪结果:
Shell
; html-script: false ](test)jhaddad@jons-mac-pro ~VIRTUAL_ENV/src$ python -m trace --trace tracing.py 1 ? --- modulename: tracing, funcname: <module> tracing.py(1): a = 1 tracing.py(2): b = 2 tracing.py(3): a = b --- modulename: trace, funcname: _unsettrace trace.py(80): sys.settrace(None) |
当你想要搞清楚其他程序的内部构造的时候,这个功能非常有用。如果你以前用过strace,它们的工作方式很相像
在一些场合,我使用pycallgraph来追踪性能问题。它可以创建函数调用时间和次数的图表。
腾讯在职8年Python开发经验的程序员写给初学者的总结,希望有用
最后,objgraph对于查找内存泄露非常有用。这里有一篇关于如何使用它查找内存泄露的好文。
Gevent
Gevent 是一个很好的库,封装了Greenlets,使得Python具备了异步调用的功能。是的,非常棒。我最爱的功能是Pool,它抽象了异步调用部分,给我们提供了可以简单使用的途径,一个异步的map()函数:
Python
; html-script: false ]from gevent import monkey monkey.patch_all() from time import sleep, time def fetch_url(url): print "Fetching %s" % url sleep(10) print "Done fetching %s" % url from gevent.pool import Pool urls = ["http://test.com", "http://bacon.com", "http://eggs.com"] p = Pool(10) start = time() p.map(fetch_url, urls) print time() - start |
非常重要的是,需要注意这段代码顶部对gevent monkey进行的补丁,如果没有它的话,就不能正确的运行。如果我们让Python连续调用 fetch_url 3次,通常我们期望这个过程花费30秒时间。使用gevent:
Python
; html-script: false ](test)jhaddad@jons-mac-pro ~VIRTUAL_ENV/src$ python g.py Fetching http://test.com Fetching http://bacon.com Fetching http://eggs.com Done fetching http://test.com Done fetching http://bacon.com Done fetching http://eggs.com 10.001791954 |
如果你有很多数据库调用或是从远程URLs获取,这是非常有用的。我并不是很喜欢回调函数,所以这一抽象对我来说效果很好。
结论
好吧,如果你看到这里了,那么你很可能已经学到了一些新东西。这些工具,在过去的一年里对我影响重大。找打它们花费了不少时间,所以希望本文能够减少其他人想要很好利用这门语言需要付出的努力。
上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。