集成测试:在测试之前在“unittest.setUp”期间启动阻塞服务器?

发布于 2024-08-24 01:35:41 字数 354 浏览 8 评论 0原文

我正在使用 Thrift 编写一项服务,并且需要应用一些测试以确保其运行/响应正如预期的那样。为了实现这一点,最可靠的方法似乎是使用 unittest 模块。

我想直接从单元测试的 setUp 方法中以“测试”模式启动服务(在特定的“测试”端口上启动,使用“测试”数据等),但调用 < code>serve() 会在此时阻塞,等待连接。

启动服务以便执行测试并使用 tearDown 方法干净地关闭服务的最佳方法是什么?

I'm writing a service using Thrift and need to apply some tests to ensure that it operates/responds as expected. To accomplish this, the most robust approach seems to be to use the unittest module.

I'd like to start the service in "test" mode (starts on a specific "test" port, uses "test" data, etc) from directly within the unit test's setUp method, but calling serve() blocks at that point waiting for connections.

What would be the best approach for starting the service so that the tests can execute and the service can be brought-down cleanly using the tearDown method?

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

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

发布评论

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

评论(3

瀟灑尐姊 2024-08-31 01:35:41

unittest 提供的“完全隔离”非常适合单元测试(它设计的目的),但不一定适合集成 em> 测试——我看到了重用 unittest 的吸引力,我自己这样做是为了利用我们周围的特殊测试运行程序和c,但是,意识到这是一种力量适合使用 unittest 进行集成测试,我尝试通过与编码单元测试不同的编码来进行补偿。

当我必须在集成测试中生成服务器时,我倾向于在模块开始时在单独的进程中生成服务器 - 通过 subprocess 或通过其他适合您的安装的方式,如果您想在单独的节点或其他节点中运行它 - 并注册 atexit 当我的测试模块全部完成时,将向服务器发送终止请求的终止代码。这并不像单元测试所要求的那样“完全分离”,但我发现它对于集成测试来说已经足够好了,并且分摊了启动和初始化服务器的开销,这实际上可能非常高,跨多个测试。

即使您热衷于使用 setUptearDown,我仍然建议使用单独的进程(和单独的节点,如果您在“连续建造农场”等)。正如 @Ned 的回答所暗示的那样,在同一进程中使用不同的线程给我带来了风险——可能很容易在服务器和测试之间产生不需要的交互,隐藏一些错误或导致其他错误。

如果我理解正确的话,你不仅试图在同一个进程上运行服务器,而且甚至在与测试相同的线程中运行服务器,这对我来说绝对是一个坏主意——当然它会阻止一切,除非服务器确实编码非常特别!-)

The "complete isolation" that unittest provides is excellent for unit tests (what it's designed for) but not necessarily for integration tests -- I see the attraction of reusing unittest for those, I do it myself to take advantage of special test runners &c that we have around, but, realizing that it's something of a force fit to use unittest for integration tests, I try to compensate by coding rather differently than I'd code unit tests.

When I have to spawn a server in integration testing, I tend to do the spawning at the start of the module, in a separate process -- via subprocess, or by other means appropriate to your installation, if you want to run it in a separate node or whatever -- and register with atexit the termination code that will send that server the termination request when my test-module is all finished. That's not as "cleanly separated" as unit testing would require, but I find it's good enough for integration testing, and amortizes the overhead of starting and initializing the server, which may be very high indeed, across multiple tests.

Even if you're keen to use setUp and tearDown, I still recommend using a separate process (and a separate node, if you have plenty of those lying around in a "continuous build farm" or the like). Using a different thread in the same process, as @Ned's answer suggests, strikes me as risky -- might easily produce unwanted interactions between the server and the tests, hiding some bug or causing others.

If I understand correctly you're trying to run the server not just on the same process, but even in the same thread as the tests, and that seems definitely a bad idea to me -- of course it will block everything, unless the server is coded very particularly indeed!-)

感性不性感 2024-08-31 01:35:41

您可以创建一个上下文管理器来在服务器在后台运行时启动测试。

if __name__ == '__main__':
    with background_server():
        print('Server loaded, launching the tests...')
        unittest.main(exit=False)

我用于 background_server 的代码:

@contextlib.contextmanager
def background_server():
    # Launching the server
    pid_server = os.fork()
    if not pid_server:  # Child code
        launch_server()  # Blocking call (until signal.SIGINT)
        print('Interuption detected, server closed...')
        sys.exit()  # Closing the process

    # HACK: Wait for the server to be launched
    while True:
        try:
            requests.get("http://localhost:5000/", timeout=0.5)
            break
        except requests.exceptions.ConnectionError:
            pass
        time.sleep(0.3)

    try:
        yield
    finally:
        # Closing the server
        os.kill(pid_server, signal.SIGINT)

You could create a context manager to launch your test while a server is running on background.

if __name__ == '__main__':
    with background_server():
        print('Server loaded, launching the tests...')
        unittest.main(exit=False)

The code I use for background_server:

@contextlib.contextmanager
def background_server():
    # Launching the server
    pid_server = os.fork()
    if not pid_server:  # Child code
        launch_server()  # Blocking call (until signal.SIGINT)
        print('Interuption detected, server closed...')
        sys.exit()  # Closing the process

    # HACK: Wait for the server to be launched
    while True:
        try:
            requests.get("http://localhost:5000/", timeout=0.5)
            break
        except requests.exceptions.ConnectionError:
            pass
        time.sleep(0.3)

    try:
        yield
    finally:
        # Closing the server
        os.kill(pid_server, signal.SIGINT)
原来分手还会想你 2024-08-31 01:35:41

如果 serve() 阻塞,那么最好的办法是在 setUp 中生成一个线程来调用 serve()。然后你必须弄清楚如何在 tearDown 方法中停止 Thrift。

If serve() blocks, then your best bet is to spawn a thread in setUp to call serve(). Then you have to figure out how to stop Thrift in the tearDown method.

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