2013-08-22 37 views
4

我在测试驱动开发中阅读official tutorial,但对我而言这并没有什么帮助。我写了一个小型库,它广泛使用了twisted.web.client.Agent及其子类(例如BrowserLikeRedirectAgent),但我一直在努力将本教程的代码调整到我自己的测试用例中。如何使用twisted.web.client.Agent及其子类为代码编写测试?

我看了一下twisted.web.test.test_web,但我不明白如何使所有的部分合在一起。举例来说,我仍然不知道如何从Agent得到一个Protocol对象,按照官方教程

可有人告诉我如何写一些代码依赖于代理GETPOST数据一个简单的测试?任何额外的细节或建议是最受欢迎的...

非常感谢!

+0

我下面贴一个答案,但我一般建议将得到充分熟悉'Deferred's和'@ inlineCallbacks'和一般非阻塞/异步编程原理和概念。此外,研究gevent并将其与Twisted及其@ @ inlineCallbacks进行比较可能会进一步了解该领域(以及为什么不是Node.js)。 –

回答

3

如何使用@inlineCallbacks使生活更简单(即代码更具可读性)。

事实上,我甚至会建议远离直接使用Deferred s,除非在性能或特定用例中绝对需要,而是始终坚持使用@inlineCallbacks - 这种方式您可以保留你的代码看起来像普通的代码,而从非阻塞行为中获益:

from twisted.internet import reactor 
from twisted.web.client import Agent 
from twisted.internet.defer import inlineCallbacks 
from twisted.trial import unittest 
from twisted.web.http_headers import Headers 
from twisted.internet.error import DNSLookupError 


class SomeTestCase(unittest.TestCase): 
    @inlineCallbacks 
    def test_smth(self): 
     ag = Agent(reactor) 
     response = yield ag.request('GET', 'http://example.com/', Headers({'User-Agent': ['Twisted Web Client Example']}), None) 
     self.assertEquals(response.code, 200) 

    @inlineCallbacks 
    def test_exception(self): 
     ag = Agent(reactor) 
     try: 
      yield ag.request('GET', 'http://exampleeee.com/', Headers({'User-Agent': ['Twisted Web Client Example']}), None) 
     except DNSLookupError: 
      pass 
     else: 
      self.fail() 

审判应该照顾其余部分(即等候在Deferred■从测试功能(返回@inlineCallbacks -wrapped可调用也“神奇”返回Deferred - 我强烈建议阅读更多有关@inlineCallbacks如果你不是家庭教师还没有)。

P.S.还有一个用于鼻子测试的扭曲“插件”,使您能够从测试功能中返回Deferred,并且有鼻子等待,直到它们在退出之前被解雇为止:http://nose.readthedocs.org/en/latest/api/twistedtools.html

+1

我接受你的回答,尽管如果你(或其他人)可以提供不涉及任何实际网络流量的解决方案,我会非常感激。不过谢谢!内联回调使其更易于管理。 – blz

+0

我会,但首先你需要帮助我理解:你想编写涉及'twisted.w.c.Agent'的测试,但想要一个“不涉及任何网络流量”的解决方案?你究竟是什么意思?嘲笑网络,只是测试“纯”的逻辑? –

+0

是的,这正是我的意思 - 理想情况下,我想通过类似于“StringTransport”对象的方式发送网络流量。 – blz

0

这个怎么样?对以下内容运行试用。基本上,你只是嘲笑代理并假装它做广告,并使用FakeAgent(在这种情况下)失败所有请求。如果你真的想将数据注入到交通工具中,那我想这将会“更多地做”。但是,你真的在​​测试你的代码吗?或代理的?

from twisted.web import client 
from twisted.internet import reactor, defer 

class BidnessLogik(object): 
    def __init__(self, agent): 
     self.agent = agent 
     self.money = None 

    def make_moneee_quik(self): 
     d = self.agent.request('GET', 'http://no.traffic.plz') 
     d.addCallback(self.made_the_money).addErrback(self.no_dice) 
     return d 

    def made_the_money(self, *args): 
     ##print "Moneeyyyy!" 
     self.money = True 
     return 'money' 

    def no_dice(self, fail): 
     ##print "Better luck next time!!" 
     self.money = False 
     return 'no dice' 

class FailingAgent(client.Agent): 
    expected_uri = 'http://no.traffic.plz' 
    expected_method = 'GET' 
    reasons = ['No Reason'] 
    test = None 

    def request(self, method, uri, **kw): 
     if self.test: 
      self.test.assertEqual(self.expected_uri, uri) 
      self.test.assertEqual(self.expected_method, method) 
      self.test.assertEqual([], kw.keys()) 
     return defer.fail(client.ResponseFailed(reasons=self.reasons, 
               response=None)) 

class TestRequest(unittest.TestCase): 
    def setUp(self): 
     self.agent = FailingAgent(reactor) 
     self.agent.test = self 

    @defer.inlineCallbacks 
    def test_foo(self): 
     bid = BidnessLogik(self.agent) 
     resp = yield bid.make_moneee_quik() 
     self.assertEqual(resp, 'no dice') 
     self.assertEqual(False, bid.money) 
2

这类似于迈克说,但试图测试响应处理。还有其他方法可以做到这一点,但我喜欢这种方式。此外,我同意测试包装代理的东西不是太有用,并且在协议中测试协议/保持逻辑可能会更好,但有时您只是想添加一些绿色标记。

class MockResponse(object): 
    def __init__(self, response_string): 
     self.response_string = response_string 

    def deliverBody(self, protocol): 
     protocol.dataReceived(self.response_string) 
     protocol.connectionLost(None) 


class MockAgentDeliverStuff(Agent): 

    def request(self, method, uri, headers=None, bodyProducer=None): 
     d = Deferred() 
     reactor.callLater(0, d.callback, MockResponse(response_body)) 
     return d 

class MyWrapperTestCase(unittest.TestCase): 

    def setUp:(self): 
     agent = MockAgentDeliverStuff(reactor) 
     self.wrapper_object = MyWrapper(agent) 

    @inlineCallbacks 
    def test_something(self): 
     response_object = yield self.wrapper_object("example.com") 
     self.assertEqual(response_object, expected_object) 
相关问题