简体   繁体   English

如何使用twisted.web.client.Agent及其子类编写代码测试?

[英]How can I write tests for code using twisted.web.client.Agent and its subclasses?

I read the official tutorial on test-driven development, but it hasn't been very helpful in my case. 我阅读了关于测试驱动开发的官方教程 ,但在我的案例中它并没有很大帮助。 I've written a small library that makes extensive use of twisted.web.client.Agent and its subclasses ( BrowserLikeRedirectAgent , for instance), but I've been struggling in adapting the tutorial's code to my own test cases. 我编写了一个小型库,它大量使用twisted.web.client.Agent及其子类(例如BrowserLikeRedirectAgent ),但我一直在努力使教程的代码适应我自己的测试用例。

I had a look at twisted.web.test.test_web , but I don't understand how to make all the pieces fit together. 我看了一下twisted.web.test.test_web ,但我不明白如何将所有部分组合在一起。 For instance, I still have no idea how to get a Protocol object from an Agent , as per the official tutorial 例如,根据官方教程,我仍然不知道如何从Agent获取Protocol对象

Can anybody show me how to write a simple test for some code that relies on Agent to GET and POST data? 任何人都可以告诉我如何编写一些依赖于代理到GETPOST数据的代码的简单测试吗? Any additional details or advice is most welcome... 我们非常欢迎任何其他细节或建议......

Many thanks! 非常感谢!

How about making life simpler (ie code more readable) by using @inlineCallbacks . 如何通过使用@inlineCallbacks使生活更简单(即代码更具可读性)。

In fact, I'd even go as far as to suggest staying away from using Deferred s directly, unless absolutely necessary for performance or in a specific use case, and instead always sticking to @inlineCallbacks —this way you'll keep your code looking like normal code, while benefitting from non-blocking behavior: 事实上,我甚至建议不要直接使用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()

Trial should take care of the rest (ie waiting on the Deferred s returned from the test functions ( @inlineCallbacks -wrapped callables also "magically" return a Deferred —I strongly suggest reading more on @inlineCallbacks if you're not familiar with it yet). 试验应该照顾其余部分(即等待从测试函数返回的Deferred s( @inlineCallbacks -wrapped callables)“神奇地”返回Deferred -I强烈建议如果你还不熟悉那么在@inlineCallbacks上阅读更多)。

PS there's also a Twisted "plugin" for nosetests that enables you to return Deferred s from your test functions and have nose wait until they are fired before exiting: http://nose.readthedocs.org/en/latest/api/twistedtools.html PS还有一个用于测试的Twisted“插件”,它允许你从测试函数中返回Deferred s并且在退出之前等待它们被解雇: http//nose.readthedocs.org/en/latest/api/twistedtools。 HTML

This is similar to what mike said, but attempts to test response handling. 这类似于迈克所说,但试图测试响应处理。 There are other ways of doing this, but I like this way. 还有其他方法可以做到这一点,但我喜欢这种方式。 Also I agree that testing things that wrap Agent isn't too helpful and testing your protocol/keeping logic in your protocol is probably better anyway but sometimes you just want to add some green ticks. 此外,我同意测试包装代理的东西不是太有用,并且在协议中测试协议/保持逻辑可能更好,但有时你只想添加一些绿色滴答。

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)

How about this? 这个怎么样? Run trial on the following. 对以下内容进行试用。 Basically you're just mocking away Agent and pretending it does as advertised, and using FakeAgent to (in this case) fail all requests. 基本上你只是嘲笑代理并假装它像宣传的那样,并且使用FakeAgent(在这种情况下)使所有请求失败。 If you actually want to inject data into the transport, that would take "more doing" I guess. 如果你真的想把数据注入到传输中,那我认为这样做会“更多”。 But are you really testing your code, then? 但是,你真的在​​测试你的代码吗? Or Agent's? 还是代理?

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM