<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>年华转瞬 &#187; decorator</title>
	<atom:link href="http://blog.xiaket.org/tag/decorator/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.xiaket.org</link>
	<description>xiaket 的网志</description>
	<lastBuildDate>Sat, 21 Aug 2010 02:31:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>用python的单元测试工具写网易微博API的测试样例</title>
		<link>http://blog.xiaket.org/2010/05/16/python-unittest-on-t163-api/</link>
		<comments>http://blog.xiaket.org/2010/05/16/python-unittest-on-t163-api/#comments</comments>
		<pubDate>Sun, 16 May 2010 14:59:45 +0000</pubDate>
		<dc:creator>xiaket</dc:creator>
				<category><![CDATA[Python开发]]></category>
		<category><![CDATA[decorator]]></category>
		<category><![CDATA[网易微博]]></category>

		<guid isPermaLink="false">http://blog.xiaket.org/?p=403</guid>
		<description><![CDATA[虽然之前在Django项目中也不完整地用过单元测试工具, 但是今天是第一次用python的单元测试工具完整写出一个项目的测试样例, 于是小记录下~

需求: 测试网易微博API的python实现.

源代码可见: http://code.google.com/p/163microblog/source/browse/trunk/tests.py

<span class="readmore"><a href="http://blog.xiaket.org/2010/05/16/python-unittest-on-t163-api/" title="用python的单元测试工具写网易微博API的测试样例">阅读全文——共2639字</a></span>]]></description>
			<content:encoded><![CDATA[<p>虽然之前在Django项目中也不完整地用过单元测试工具, 但是今天是第一次用python的单元测试工具完整写出一个项目的测试样例, 于是小记录下~</p>
<p>需求: 测试网易微博API的python实现.</p>
<p>源代码可见: <a href="http://code.google.com/p/163microblog/source/browse/trunk/tests.py" target="_blank">http://code.google.com/p/163microblog/source/browse/trunk/tests.py</a></p>
<p>话说对于偶这种初级民工, 写代码喜欢不需要动脑子地先搭个架子出来然后往里面填空, 不过偶连这个架子也是从python文档里面抄出来的:</p>
<pre class="brush: python;">
import unittest

from session import T163Session as Session

class SessionTests(unittest.TestCase):

    def testlogin(self):
        self.session = Session(username=&quot;xiaket@163.com&quot;, password=&quot;notmypass&quot;)
        self.assertEqual(self.session.screen_name, &quot;xiaket&quot;)

if __name__ == &quot;__main__&quot;:
    unittest.main()
</pre>
<p>这个东西貌似是能够跑, 但是有个比较不爽的地方是密码必须放到测试样例里面去, 这个让偶很不爽. 于是网上搜了搜, 看到一个继承unittest.TestCase这个基类的__init__方法的办法:</p>
<pre class="brush: python;">
import unittest

from session import T163Session as Session

class SessionTests(unittest.TestCase):

    def __init__(self, testname, username=None, password=None):
        super(SessionTests, self).__init__(testname)
        self.username = username
        self.password = password

    def testlogin(self):
        session = Session(username=self.username, password=self.password)
        self.assertEqual(session.screen_name, &quot;xiaket&quot;)
</pre>
<p>这样你在另外一个文件里面就能够对这个类进行测试了:</p>
<pre class="brush: python;">
import unittest

from t163.tests import SessionTests

if __name__ == &quot;__main__&quot;:
    username = &quot;xiaket@163.com&quot;
    password = &quot;notmypass&quot;
    suite = unittest.TestSuite()
    suite.addTest(SessionTests(&quot;testlogin&quot;, username, password))
    unittest.TextTestRunner().run(suite)
</pre>
<p>架子搭好了, 剩下的就是苦力活, 往里面填测试样例了. 这个过程比较纠结比较繁复, 而且伴随着测试样例的逐渐完成, 我还fix了一群以前代码中的bug. 另外, 由于现在网易微博还比较不成熟, 我还不得不为一群server的错误擦屁股, 写了几个装饰器来修正API的行为. 例如, 有个微博的API能够给出follow某用户的用户的信息.当给出的用户的screen_name参数不正确时, 我们理应期待服务器返回错误代码. 但是服务器比较出人意料地返回了follow当前登录用户的用户的信息. 这导致所有查询都不是完全可靠的, 除非你在每次查询前确定你查询所使用的screen_name是有效的. 于是, 我写了这样一个装饰器加到已有函数的前面:</p>
<pre class="brush: python;">
def check_screen_name(func):
    &quot;&quot;&quot;
    This decorator would check the screen_name in the parameter of the original
    function.

    It is to be noted that the screen must be the first argument if we are
    using a positional parameter.
    &quot;&quot;&quot;
    def morewrapped(func):
        def wrapped(kls, *args, **kwargs):
            if 'screen_name' in kwargs:
                _screen_name = kwargs['screen_name']
            elif len(args):
                _screen_name = args[0]
            else:
                _screen_name = None
            if _screen_name:
                # If the screen_name is set, we shall check if it is a valid
                # screen_name. We do this by visiting the homepage of this
                # screen_name:
                _url = &quot;/%s&quot; % _screen_name
                _message = &quot;Specified user does not exist.&quot;
                _err_dict = {
                    404: (UserNotFound, _message),
                }
                kls.request(_url, errors=_err_dict)
            return func(kls, *args, **kwargs)
        return wrapped
    return morewrapped(func)
</pre>
<p>我们通过能否访问这个用户的主页来判断这个用户是否存在. 如果这个主页不能够被正常访问, 我们就抛出一个404, 这样就能相信followers这个API的结果了. 另外, 使用装饰器的好处在于, 哪天服务器端的程序更新了, 我们的代码不用做太大的修改就可以继续使用.</p>
<p>好吧, 话题扯回来, 总结下写了这么长时间的测试样例, 有啥经验:</p>
<ul>
<li>将测试代码分类, 这样什么时候改动了一个地方, 不需要测试所有的样例.</li>
<li>这个项目主要测试的内容是异常的处理, 于是可以先写好所有的会抛异常的代码, 然后一边测试一边添加assert语句.</li>
<li>考虑问题要全面, 当然这个比较废话了, 每个人都希望如此.</li>
<li>如果测试需要网络交互, 或者速度较慢的话, 用&#8221;"&#8221;将测过的不影响逻辑的代码注释起来, 这样能有效地提高速度.</li>
<li>注意添加注释, 这样你能够更有效地重用你自己的代码.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.xiaket.org/2010/05/16/python-unittest-on-t163-api/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>一个很有用的Django装饰器: render_to</title>
		<link>http://blog.xiaket.org/2009/12/04/django-decorator-render_to/</link>
		<comments>http://blog.xiaket.org/2009/12/04/django-decorator-render_to/#comments</comments>
		<pubDate>Fri, 04 Dec 2009 09:52:14 +0000</pubDate>
		<dc:creator>xiaket</dc:creator>
				<category><![CDATA[Django开发]]></category>
		<category><![CDATA[decorator]]></category>
		<category><![CDATA[Python开发]]></category>

		<guid isPermaLink="false">http://blog.xiaket.org/?p=156</guid>
		<description><![CDATA[今天在pypi里面乱逛时看到一个装饰器, 觉得比较赞:



def render_to(template=None):

<span class="readmore"><a href="http://blog.xiaket.org/2009/12/04/django-decorator-render_to/" title="一个很有用的Django装饰器: render_to">阅读全文——共1487字</a></span>]]></description>
			<content:encoded><![CDATA[<p>今天在pypi里面乱逛时看到一个装饰器, 觉得比较赞:</p>
<pre class="brush: python;">
def render_to(template=None):
    &quot;&quot;&quot;
    Decorator for Django views that sends returned dict to render_to_response function.

    Template name can be decorator parameter or TEMPLATE item in returned dictionary.
    RequestContext always added as context instance.
    If view doesn't return dict then decorator simply returns output.

    Parameters:
     - template: template name to use

    Examples:
    # 1. Template name in decorator parameters

    @render_to('template.html')
    def foo(request):
        bar = Bar.object.all()
        return {'bar': bar}

    # equals to
    def foo(request):
        bar = Bar.object.all()
        return render_to_response('template.html',
                                  {'bar': bar},
                                  context_instance=RequestContext(request))
    # 2. Template name as TEMPLATE item value in return dictionary

    @render_to()
    def foo(request, category):
        template_name = '%s.html' % category
        return {'bar': bar, 'TEMPLATE': template_name}

    #equals to
    def foo(request, category):
        template_name = '%s.html' % category
        return render_to_response(template_name,
                                  {'bar': bar},
                                  context_instance=RequestContext(request))

    &quot;&quot;&quot;
    def renderer(function):
        def wrapper(request, *args, **kwargs):
            output = function(request, *args, **kwargs)
            if not isinstance(output, dict):
                return output
            tmpl = output.pop('TEMPLATE', template)
            return render_to_response(tmpl, output, context_instance=RequestContext(request))
        return wrapper
    return renderer
</pre>
<p>这个装饰器出自<a href="http://pypi.python.org/pypi/django-annoying/0.7.4">django-annoying</a>. 在annoying目录下的decorators.py文件中.</p>
<p>优点: 写视图函数的时候, 总是写一个很长的render_to_response函数, 这个里面的东西都是很固定的. 于是每次都是y来p去, 很不爽. 如果用这个装饰器就可以很一目了然地在视图函数中用docstring里面的格式来写视图函数了. 这个时候, 视图函数返回一个字典就可以了.</p>
<p>缺点: 对于熟悉Django的用户, 这个可读性稍差了一点点. 不过我想习惯了这个装饰器的人都会更爱这个吧, 毕竟它更pythonic, 更DRY.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.xiaket.org/2009/12/04/django-decorator-render_to/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
