单元测试twisted.web.client.Agent没有网络

时间:2014-06-09 11:56:59

标签: unit-testing twisted trial twisted.web

我几年没有做任何扭曲,并且已经开始使用较新的Agent风格的客户端http调用。使用Agent一直没问题,但测试让我很困惑(毕竟它已经扭曲了)。

我已经浏览了https://twistedmatrix.com/documents/current/core/howto/trial.html文档以及有关试用工具和代理本身的API。还有很多搜索。

我已经伪造了Agent,因为我不需要测试它。但是由于处理代理请求的处理和响应的步骤,我的测试代码变得讨厌,实现代理,协议等的嵌套层。我应该在哪里绘制这条线并且有一些工具我是避风港找不到?

这是一个最小的例子(SUT的幼稚实现):

from twisted.web.client import Agent, readBody
from twisted.internet import reactor
import json

class SystemUnderTest(object):

    def __init__(self, url):
        self.url = url

    def action(self):
        d = self._makeAgent().request("GET", self.url)
        d.addCallback(self._cbSuccess)
        return d

    def _makeAgent(self):
        ''' It's own method so can be overridden in tests '''
        return Agent(reactor)

    def _cbSuccess(self, response):
        d = readBody(response)
        d.addCallback(self._cbParse)
        return d

    def _cbParse(self, data):
        self.result = json.loads(data)
        print self.result

使用测试模块:

from twisted.trial import unittest
from sut import SystemUnderTest
from twisted.internet import defer
from twisted.test import proto_helpers

class Test(unittest.TestCase):

    def test1(self):
        s_u_t = ExtendedSystemUnderTest(None)
        d = s_u_t.action()
        d.addCallback(self._checks, s_u_t)
        return d

    def _checks(self, result, s_u_t):
        print result
        self.assertEqual({'one':1}, s_u_t.result)


class ExtendedSystemUnderTest(SystemUnderTest):

    def _makeAgent(self):
        return FakeSuccessfulAgent("{'one':1}")

## Getting ridiculous below here...

class FakeReason(object):
    def check(self, _):
        return False
    def __str__(self):
        return "It's my reason"

class FakeResponse(object):
    ''' Implementation of IResponse '''
    def __init__(self, content):
        self.content = content
        self.prot = proto_helpers.StringTransport()
        self.code = 200
        self.phrase = ''

    def deliverBody(self, prot):
        prot.makeConnection(self.prot)
        prot.dataReceived(self.content)
#        reason = FakeReason()
#        prot.connectionLost(reason)

class FakeSuccessfulAgent(object):
    ''' Implementation of IAgent '''
    def __init__(self, response):
        self.response = response

    def request(self, method, url):
        return defer.succeed(FakeResponse(self.response))

1 个答案:

答案 0 :(得分:2)

  

但测试令我感到困惑(毕竟它是扭曲的)。

热闹。

class ExtendedSystemUnderTest(SystemUnderTest):
    def _makeAgent(self):
        return FakeSuccessfulAgent("{'one':1}")

我建议你让代理使用普通参数。这比_makeAgent之类的私有方法更方便。组成很棒。继承就是meh。

class FakeReason(object):
    ...

没有理由假装这个。只需使用twisted.python.failure.Failure即可。您不会 伪造测试中的每个对象。如果你不假装它们就会妨碍你。

class FakeResponse(object):
    ...

这可能是好的和必要的。

class FakeSuccessfulAgent(object):
    ...

这也很可能是必要的。你应该让它实际上更像是IAgent实现 - 声明它实现了接口,使用zope.interface.verify.verify{Class,Object}来确保你得到实现写入等(例如request有错误现在签名)。

实际上是将所有这些测试工具添加到Twisted自身的票证 - https://twistedmatrix.com/trac/ticket/4024。所以我不认为你真的很困惑,你基本上和项目本身在同一条轨道上。您只是因为Twisted尚未为您完成所有这些工作而感到痛苦。

另外,请注意,而不是:

class Test(unittest.TestCase):

    def test1(self):
        s_u_t = ExtendedSystemUnderTest(None)
        d = s_u_t.action()
        d.addCallback(self._checks, s_u_t)
        return d

你可以写这样的东西(最好是这样):

class Test(unittest.TestCase):

    def test1(self):
        s_u_t = ExtendedSystemUnderTest(None)
        d = s_u_t.action()
        self._checks(s_u_t, self.successResultOf(d))

这是因为IAgent的假实现是同步的。你知道它是同步的。到request返回时,它返回的Deferred已经有了结果。以这种方式编写测试意味着您可以稍微简化代码(即,您可以在某种程度上忽略它的异步性 - 因为它不是)并且它避免运行全局反应器是在试验中从测试方法返回Deferred的原因。