Python:单元测试基于套接字的代码?

发布于 2024-09-30 01:34:47 字数 227 浏览 9 评论 0原文

我正在编写一个 Python 客户端+服务器,它使用 gevent.socket 进行通信。是否有任何好的方法来测试代码的套接字级操作(例如,验证使用无效证书的 SSL 连接是否会被拒绝)?或者最简单的方法是生成一个真实的服务器?

编辑:我不认为“天真的”模拟足以测试 SSL 组件,因为涉及复杂的交互。我这样说有错吗?或者有更好的方法来测试 SSL 的东西吗?

I'm writing a Python client+server that uses gevent.socket for communication. Are there any good ways of testing the socket-level operation of the code (for example, verifying that SSL connections with an invalid certificate will be rejected)? Or is it simplest to just spawn a real server?

Edit: I don't believe that "naive" mocking will be sufficient to test the SSL components because of the complex interactions involved. Am I wrong in that? Or is there a better way to test SSL'd stuff?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

抽个烟儿 2024-10-07 01:34:47

您可以轻松启动服务器,然后在测试用例中访问它。 gevent 的 自己的测试套件 正是用于测试 gevent 的 内置服务器

例如:

class SimpleServer(gevent.server.StreamServer):

    def handle(self, socket, address):
        socket.sendall('hello and goodbye!')

class Test(unittest.TestCase):      

    def test(self):
        server = SimpleServer(('127.0.0.1', 0))
        server.start()
        client = gevent.socket.create_connection(('127.0.0.1', server.server_port))
        response = client.makefile().read()
        assert response == 'hello and goodbye!'
        server.stop()

使用 0 作为端口值意味着服务器将使用任何可用端口。服务器启动后,bind 选择的实际值可作为 server_port 属性使用。

StreamServer 也支持 SSL,将 keyfilecertfile 参数传递给构造函数,它会在之前用 SSLObject 包装每个套接字将其传递给您的处理程序。

如果您不使用 StreamServer 并且您的服务器基于 Greenlet那么确实生成这就是你应该做的。不要忘记在测试用例结束时杀死它。

gevent 中,启动服务器和生成 greenlet 是快速操作,比创建新线程或进程快得多,您可以轻松地为每个测试用例创建一个新服务器。只是不要忘记在不再需要服务器时立即进行清理。

我相信没有必要模拟任何 gevent API,使用它会更容易,因为服务器和客户端可以愉快地生活在同一个进程中。

You can easily start a server and then access it in a test case. The gevent's own test suite does exactly that for testing gevent's built-in servers.

For example:

class SimpleServer(gevent.server.StreamServer):

    def handle(self, socket, address):
        socket.sendall('hello and goodbye!')

class Test(unittest.TestCase):      

    def test(self):
        server = SimpleServer(('127.0.0.1', 0))
        server.start()
        client = gevent.socket.create_connection(('127.0.0.1', server.server_port))
        response = client.makefile().read()
        assert response == 'hello and goodbye!'
        server.stop()

Using 0 for the port value means the server will use any available port. After the server is started, the actual value chosen by bind is available as server_port attribute.

StreamServer supports SSL too, pass keyfile and certfile arguments to the constructor and it will wrap each socket with SSLObject before passing it to your handler.

If you don't use StreamServer and your server is based on Greenlet then indeed spawning it is what you should do. Don't forget to kill it at the end of the test case.

Starting a server and spawning a greenlet are fast operations in gevent, much faster than creating a new thread or process and you can easily create a new server for each test case. Just don't forget to cleanup as soon as you don't need the server anymore.

I believe there's no need to mock any of gevent API, it's much easier just to use it as servers and clients can happily live within the same process.

灯角 2024-10-07 01:34:47

模拟和存根很棒,但有时您需要将其提升到下一个集成级别。由于生成服务器(即使是假的服务器)可能需要一些时间,因此考虑一个单独的测试套件(称为集成测试)可能是合适的。

“像要使用它一样测试它”是我的指导方针,如果你模拟和存根太多以至于你的测试变得微不足道,那么它就没那么有用(尽管几乎任何测试都比没有好)。如果您担心处理不良 SSL 证书,请务必制作一些不良证书并编写一个可以将其提供给的测试装置。如果这意味着生成一个服务器,那就这样吧。也许如果这让你足够烦恼的话,它会导致重构,使其可以以另一种方式进行测试。

Mocking and stubbing are great, but sometimes you need to take it up to the next level of integration. Since spawning a server, even a fakeish one, can take some time, consider a separate test suite (call them integration tests) might be in order.

"Test it like you are going to use it" is my guideline, and if you mock and stub so much that your test becomes trivial it's not that useful (though almost any test is better than none). If you are concerned about handling bad SSL certs, by all means make some bad ones and write a test fixture you can feed them to. If that means spawning a server, so be it. Maybe if that bugs you enough it will lead to a refactoring that will make it testable another way.

撩心不撩汉 2024-10-07 01:34:47

还有另一种(IMO 更好)方法:您应该模拟您正在使用的库。
Python 的模拟助手示例是 mox

您不需要一组具有有效证书的服务器,另一组具有无效证书的服务器,根本没有 ssl 支持,根本不响应任何数据包,等等。您可以使用“虚拟”客户端套接字来模拟它们的行为。它与 Mox 的工作方式是,您首先“教导”它应该期望什么以及它应该如何反应,然后在其上执行您的真实代码,同时将真实的 gevent.socket 替换为模拟的 gevent.socket。需要一些练习才能掌握它的窍门,但这是值得的。

There is another (IMO better) way: You should mock the library you are using.
An example mocking helper for python is mox.

You don't need a set of servers with a valid certificate, another with an invalid certificate, with no ssl support at all, ones not responding to any packets at all, etc. You can simulate their behavior with a "dummy" client socket. The way it works with Mox is You first "teach" what it should expect and how it should react and then You execute Your real code on it while swapping the real gevent.socket for the mocked one. It requires some practice to get the hang of it, but it's worth it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文