扭曲的海螺试验 TDD,"StringTransport instance has no attribute..."

twisted conch trial TDD, "StringTransport instance has no attribute..."

我正在设置一个可配置的 SSH 存根 shell,类似于 MockSSH,我想以测试驱动的方式进行。

当我使用 conch.recvline.HistoricRecvLine 而不是基础 twisted.internet.protocol.Protocol

时,我正在 运行 进行问题测试
# test.py
from twisted.trial import unittest
from twisted.test.proto_helpers import StringTransportenter code here

class ShellTest(unittest.TestCase):
    def setUp(self):
        shell_factory = StubShell.ShellFactory()
        self.shell = shell_factory.buildProtocol(('127.0.0.1', 0))
        self.transport = StringTransport()
        self.shell.makeConnection(self.transport)

    def test_echo(self):
        self.shell.lineReceived('irrelevant')
        self.assertEqual(self.transport.value(), 'something')

# shell.py
from twisted.internet import protocol

class ShellProtocol(HistoricRecvLine):

    def connectionMade(self):
        HistoricRecvLine.connectionMade(self)

    def lineReceived(self, line):
        self.terminal.write('line received')

class ShellFactory(protocol.Factory):
    protocol = ShellProtocol

这按预期工作。但是,当我进行更改时:

class ShellProtocol(HistoricRecvLine):

我收到错误:

exceptions.AttributeError: StringTransport instance has no attribute 'LEFT_ARROW'

下一步: 多亏了 Glyph 的帮助,我取得了一些进展,仍在尝试进行最低限度的测试设置,以确保我正确设置了 HistoricRecvLine 协议。 我从 test_recvline.py 偷了一些代码,这对我来说仍然有点神奇,尤其是设置 sp.factory = self(unittest.Testcase)。我一直在努力将其降低到最低限度以使该测试通过。

class ShellTestConch(unittest.TestCase):

def setUp(self):
    self.sp = insults.ServerProtocol()
    self.transport = StringTransport()
    self.my_shell = StubShell.ShellProtocol()
    self.sp.protocolFactory = lambda: self.my_shell
    self.sp.factory = self
    self.sp.makeConnection(self.transport)

这让我更接近预期的输出,但是现在我看到终端对输出进行了很大的破坏,这应该是预料之中的。

twisted.trial.unittest.FailTest: '\x1bc>>> \x1b[4hline received' != 'line received'

出于 TDD 的目的,我不确定我是否应该只接受输出的 '\x1bc>>>...' 版本(至少在我通过设置自定义提示打破它之前)或尝试覆盖 shell 提示以获得干净的输出。

问得好;感谢您的提问(也感谢您使用 Twisted,并进行 TDD :-))。

HistoricRecvLine is a TerminalProtocol, which provides ITerminalProtocol. ITerminalProtocol.makeConnection must be called with a provider of an ITerminalTransport. On the other hand, your unit test is calling your ShellProtocol.makeConnection with an instance of StringTransport, which provides only IConsumer, IPushProducer, and ITransport.

因为 ShellProtocol.makeConnection 需要一个 ITerminalTransport,它希望它可以调用它的所有方法。不幸的是,LEFT_ARROW没有正式记录在这个接口上,这是一个疏忽,但是 Twisted 中这个接口的提供者也提供了那个属性。

你想要做的是在你的 ITerminalProtocol 周围包裹一个 ServerProtocol,在进程将作为您的ITerminalTransport。您可以在 twisted.conch.stdio.

中看到此组合的一个简单示例