如何在Python单元测试中从命令行启动服务器

如何在Python单元测试中从命令行启动服务器,python,unit-testing,subprocess,Python,Unit Testing,Subprocess,我正在为一个Python脚本构建一个测试程序,该脚本可以与数据库一起工作。作为setUp()方法的一部分,我试图让测试仪在端口28016上的localhost上启动RejectionDB服务器,以防尚未启动 我正在使用子进程启动服务器。问题在于,根据,subprocess等待命令完成。在这种情况下,似乎只要服务器启动并运行,该过程就不会完成,测试不会在setUp()阶段之后继续进行 以下是我正在尝试的脚本: import unittest import rethinkdb as r import

我正在为一个Python脚本构建一个测试程序,该脚本可以与数据库一起工作。作为
setUp()
方法的一部分,我试图让测试仪在端口
28016
上的
localhost
上启动RejectionDB服务器,以防尚未启动

我正在使用
子进程
启动服务器。问题在于,根据,
subprocess
等待命令完成。在这种情况下,似乎只要服务器启动并运行,该过程就不会完成,测试不会在
setUp()
阶段之后继续进行

以下是我正在尝试的脚本:

import unittest
import rethinkdb as r
import subprocess

class TestController(unittest.TestCase):

    HOST = "localhost"
    PORT_OFFSET = 1
    PORT = 28015 + PORT_OFFSET
    DB = "ipercron"
    TABLE = "sensor_data"


    def setUp(self):
        try:
            self.conn = r.connect(self.HOST, self.PORT)
        except r.ReqlDriverError:
            print("The RethinkDB server is not yet ready. Starting it up...")
            subprocess.call(["rethinkdb", "--port-offset", str(TestController.PORT_OFFSET)])
            self.conn = r.connect(self.HOST, self.PORT)

        if TestController.DB not in r.db_list().run(self.conn):
            r.db_create(TestController.DB).run(self.conn)
            self.conn.use(TestController.DB)

        if TestController.TABLE not in r.table_list().run(self.conn):
            r.table_create(TestController.TABLE).run(self.conn)        # Create the table if it does not yet exist

        r.table(TestController.TABLE).delete().run(self.conn)          # Empty the table to start with a clean slate

    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

suite = unittest.TestLoader().loadTestsFromTestCase(TestController)
unittest.TextTestRunner(verbosity=2).run(suite)
子进程
用于在命令行上执行
REJECTDB--port offset 1
命令,然后继续执行脚本。但是,当我运行脚本时,通常会收到一条消息,即服务器已准备就绪:

kurt@kurt-ThinkPad:~/dev/clones/ipercron-compose/controller$ python unittest_controller.py
test_upper (__main__.TestController) ... The RethinkDB server is not yet ready. Starting it up...
Running rethinkdb 2.3.5~0xenial (GCC 5.3.1)...
Running on Linux 4.4.0-42-generic x86_64
Loading data from directory /home/kurt/dev/clones/ipercron-compose/controller/rethinkdb_data
Listening for intracluster connections on port 29016
Listening for client driver connections on port 28016
Listening for administrative HTTP connections on port 8081
Listening on cluster addresses: 127.0.0.1, 127.0.1.1, ::1
Listening on driver addresses: 127.0.0.1, 127.0.1.1, ::1
Listening on http addresses: 127.0.0.1, 127.0.1.1, ::1
To fully expose RethinkDB on the network, bind to all addresses by running rethinkdb with the `--bind all` command line option.
Server ready, "kurt_ThinkPad_a0k" 07bb35f6-3a33-4e8b-9e9c-a78504457969

没有任何进一步的行动。如何使unittest继续进行测试?

请尝试以下代码

subprocess.call(["rethinkdb", "--port-offset", str(TestController.PORT_OFFSET)], shell = True)

问题是,正如您所说的,它将等待命令完成。对于需要在不等待子进程完成的情况下生成子进程的场景,可以使用:


这将返回一个提供了一整套非常有用的方法来与子进程通信的方法。例如,您可能希望在单元测试的
tearDown()
函数中使用
process.kill()
来关闭数据库。

为了让它工作,我必须输入
time.sleep()
命令,给服务器一段时间来启动和运行。我认为没有办法等到服务器运行,例如通过解析标准输出?
Popen
公开一个类似文件的对象,您可以从中读取该对象,直到看到服务器已启动,但实现起来可能有点繁琐。一个更简单的选择可能是使用类似的东西,如果您不介意引入新的依赖项的话。
process = subprocess.Popen(["rethinkdb", "--port-offset", str(TestController.PORT_OFFSET)])