我正在尝试创建一个使用DNS查询执行某些测试的测试。我试图创建一个最小的测试,它启动一个侦听DNS服务器,并使用扭曲的解析器来查询此服务器:
from twisted.trial import unittest
from twisted.internet import reactor, defer
from twisted.names import client, dns, error, server
class Tester(unittest.TestCase):
def setUp(self):
self.resolver = client.Resolver(resolv='/etc/resolv.conf')
self.resolver = client.Resolver(servers=[('127.0.0.1', 1025)])
self.factory = server.DNSServerFactory(clients=[self.resolver])
self.protocol = dns.DNSDatagramProtocol(controller=self.factory)
self.port = reactor.listenUDP(1025, self.protocol)
def tearDown(self):
self.port.stopListening()
def test_test(self):
def callback(ignore):
print("Received callback!")
res = client.createResolver(servers=[('127.0.0.1', 1025)], resolvconf='/dev/null', hosts='/dev/null')
d = res.lookupAddress('foobar.com')
d.addCallback(callback)
运行此测试会导致以下错误:
[ERROR]
Traceback (most recent call last):
Failure: twisted.trial.util.DirtyReactorAggregateError: Reactor was unclean.
DelayedCalls: (set twisted.internet.base.DelayedCall.debug = True to debug)
<DelayedCall 0x7f44c69042e8 [0.9992678165435791s] called=0 cancelled=0
DNSMixin._clearFailed(<Deferred at 0x7f44c6904358>, 28457)>
<DelayedCall 0x7f44c68f3e10 [59.99872899055481s] called=0 cancelled=0 Resolver.maybeParseConfig()>
test.Tester.test_test
==================================================================
[ERROR]
Traceback (most recent call last):
Failure: twisted.trial.util.DirtyReactorAggregateError: Reactor was
unclean.
Selectables:
<<class 'twisted.names.dns.DNSDatagramProtocol'> on 34529>
test.Tester.test_test
-------------------------------------------------------------------------------
Ran 1 tests in 0.003s
所以似乎反应堆没有从test_test中的解析器发送的消息中清除。
我不明白为什么会这样。文件说试运行反应堆,我不应该碰它。我是否错误地使用了测试框架?
您可能不应该在测试套件中进行真正的网络流量。真正的网络是片状的,依赖它的测试套件往往容易出错并且令人沮丧。你真的不希望你的测试运行失败只是因为systemd-resolved已经更新并开始对它注意到的在你的系统中传递的某些DNS流量做一些古怪的事情。
避免实际网络流量的主要策略是将接口的替代实现低于您正在测试的接口的一个级别 - 这种实现根本不使用真实网络。我的首选策略是使用简单的内存中对象模拟网络行为。如果需要,您可以针对实际和内存实现运行针对该较低级别的测试套件,并且至少在某些时候验证两个实现是“相同的”。
也就是说,你的tearDown
有一个简单的错误。它调用stopListening
返回Deferred
,但它不返回Deferred
本身。因此,试验决定在tearDown
返回时进行清理,但可能还没有。返回stopListening
Deferred
,你可以避免一个不洁的错误。
在test_test
有一个类似的错误。它不会返回d
,因此一旦方法返回,试验就会决定测试结束(成功)。返回d
并且当d
发射时它将决定测试结束(并且只有在成功结果发射时才通过测试)。