在 Twisted 试用单元测试中使用 @inlineCallbacks

Using @inlineCallbacks in Twisted trial unit tests

我有一些试用单元测试。在我的代码库中,一些方法 return 延迟并添加了回调,而其他方法则用 @inlineCallbacks 修饰。我想 运行 没有反应堆的测试,因为有些方法不做任何 I/O。我认为 @inlineCallbacks 只是 return 一个延迟,所以调用回调(0)来触发它就足够了。好像不是这样的。这是一个最小的例子:

from twisted.trial import unittest
from twisted.internet.defer import inlineCallbacks, returnValue, Deferred


def addone(val):
    d = Deferred()
    def cbk(res):
        return val + 1
    d.addCallback(cbk)
    return d


@inlineCallbacks
def call_addone(val):
    res = yield addone(val)
    returnValue(res)


class Tester(unittest.TestCase):

    def test_addone(self):
        d = addone(2)
        d.callback(0)   # whatever I pass is ignored
        self.assertEqual(3, self.successResultOf(d))

    def test_call_addone(self):
        d = call_addone(4)
        d.callback(0)   # whatever I pass is set as deferred's result
        self.assertEqual(5, self.successResultOf(d))

当我调用 addone(2) 时,我得到一个延迟,当我用回调 (0) 触发它时,它将 return 2+1。在这种情况下,传递给回调的值将被忽略。 在第二个测试中 call_addone(4) returns 也被推迟了。但在这种情况下,传递给它的参数将被忽略,return 值将是我传递给 callback() 的任何值。为什么?我显然遗漏了一些东西。

这是试用 运行ner 的输出:

test_trial
  Tester
    test_addone ...                                                        [OK]
    test_call_addone ...                                                 [FAIL]

===============================================================================
[FAIL]
Traceback (most recent call last):
  File "tests/test_trial.py", line 31, in test_call_addone
    self.assertEqual(5, self.successResultOf(d))
  File "/home/b/.local/share/virtualenvs/twproba-y019OThE/lib/python3.5/site-packages/twisted/trial/_synctest.py", line 432, in assertEqual
    super(_Assertions, self).assertEqual(first, second, msg)
  File "/usr/lib/python3.5/unittest/case.py", line 821, in assertEqual
    assertion_func(first, second, msg=msg)
  File "/usr/lib/python3.5/unittest/case.py", line 814, in _baseAssertEqual
    raise self.failureException(msg)
twisted.trial.unittest.FailTest: 5 != 0

test_trial.Tester.test_call_addone
-------------------------------------------------------------------------------
Ran 2 tests in 0.029s

FAILED (failures=1, successes=1)

这些行非常错误(假定 call_addone 是用 inlineCallbacks 定义的):

    d = call_addone(4)
    d.callback(0)   # whatever I pass is set as deferred's result

这伴随着这些行很奇怪(假设未使用 inlineCallbacks):

    d = addone(2)
    d.callback(0)   # whatever I pass is ignored

在这两种情况下,您都要求一些库代码创建 Deferred,然后您的应用程序代码为 Deferred 提供结果。因为 addone 做你想做的事,显然 可以 以这种方式使用 Deferred。但是,这不是一个好的做法。最佳做法是负责 creatingfiring a Deferred 躺在同一个地方。因此,在这种情况下,随着 addone.

的实施

你失败的测试失败的原因是你没有考虑 inlineCallbacks 的实现,它认为它确实负责触发 Deferred 它 returns。 Deferred 它 returns 是 而不是 addone 调用返回的 Deferred。它保留 Deferred 给自己。

d 的结果在:

    d = call_addone(4)
    d.callback(0)   # whatever I pass is set as deferred's result

0 正是因为您提供了 0 的结果。您已经将结果提供给 inlineCallbacks-managed Deferred 并短路了所有其余的inlineCallbacks 的实施。如果 addone 返回的 Deferred 曾经触发过,您可能会看到 AlreadyCalledError,因为 inlineCallbacks 会尝试向 d 提供结果,Deferred 你已经提供了一个结果给。