本文介绍了如何为用Python编写的DBUS服务编写功能测试?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(标题是:如何为用Python编写的DBUS服务编写单元测试?)

(Title was: "How to write a unit test for a DBUS service written in Python?")

我已经开始使用dbus编写DBUS服务-python,但是在编写测​​试用例时遇到了麻烦。

I've started to write a DBUS service using dbus-python, but I'm having trouble writing a test case for it.

这里是我尝试创建的测试示例。注意,我已经在setUp()中放入了一个GLib事件循环,这就是问题所在的地方:

Here is an example of the test I am trying to create. Notice that I have put a GLib event loop in the setUp(), this is where the problem hits:

import unittest

import gobject
import dbus
import dbus.service
import dbus.glib

class MyDBUSService(dbus.service.Object):
    def __init__(self):
        bus_name = dbus.service.BusName('test.helloservice', bus = dbus.SessionBus())
        dbus.service.Object.__init__(self, bus_name, '/test/helloservice')

    @dbus.service.method('test.helloservice')
    def hello(self):
        return "Hello World!"


class BaseTestCase(unittest.TestCase):

    def setUp(self):
        myservice = MyDBUSService()
        loop = gobject.MainLoop()
        loop.run()
        # === Test blocks here ===

    def testHelloService(self):
        bus = dbus.SessionBus()
        helloservice = bus.get_object('test.helloservice', '/test/helloservice')
        hello = helloservice.get_dbus_method('hello', 'test.helloservice')
        assert hello() == "Hello World!"

if __name__ == '__main__':
    unittest.main()

我的问题是DBUS实现需要您启动事件循环,以便它可以开始调度事件。常用的方法是使用GLib的gobject.MainLoop()。start()(尽管如果有人有更好的建议,我不喜欢这种方法)。如果您不启动事件循环,该服务仍会阻塞,您也无法查询它。

My problem is that the DBUS implementation requires you to start an event loop so that it can start dispatching events. The common approach is to use GLib's gobject.MainLoop().start() (although I'm not married to this approach, if someone has a better suggestion). If you don't start an event loop, the service still blocks, and you also cannot query it.

如果我在测试中启动服务,则事件循环会阻塞完成测试。我知道该服务正在运行,因为我可以使用qdbus工具从外部查询该服务,但是无法在启动该服务的测试中自动执行该操作。

If I start my service in the test, the event loop blocks the test from completing. I know the service is working because I can query the service externally using the qdbus tool, but I can't automate this inside the test that starts it.

考虑在测试中进行某种处理以解决此问题,但是我希望有人可以提供更整洁的解决方案,或者至少是我编写这样的测试的一个很好的起点。

I'm considering doing some kind of process forking inside the test to handle this, but I was hoping someone might have a neater solution, or at least a good starting place for how I would write a test like this.

推荐答案

在Ali A的帖子的帮助下,我设法解决了我的问题。阻塞事件循环需要启动到一个单独的进程中,以便它可以侦听事件而不会阻塞测试。

With some help from Ali A's post, I have managed to solve my problem. The blocking event loop needed to be launched into a separate process, so that it can listen for events without blocking the test.

请注意,我的问题标题包含一些错误的术语,我试图编写一个功能测试,而不是单元测试。我知道这种区别,但是直到后来才意识到自己的错误。

Please be aware my question title contained some incorrect terminology, I was trying to write a functional test, as opposed to a unit test. I was aware of the distinction, but didn't realise my mistake until later.

我已经调整了问题中的示例。它大致类似于 test_pidavim.py示例,但是对 dbus.glib使用导入来处理glib循环依赖关系,而不是对所有DBusGMainLoop东西进行编码:

I've adjusted the example in my question. It loosely resembles the "test_pidavim.py" example, but uses an import for "dbus.glib" to handle the glib loop dependencies instead of coding in all the DBusGMainLoop stuff:

import unittest

import os
import sys
import subprocess
import time

import dbus
import dbus.service
import dbus.glib
import gobject

class MyDBUSService(dbus.service.Object):

    def __init__(self):
        bus_name = dbus.service.BusName('test.helloservice', bus = dbus.SessionBus())
        dbus.service.Object.__init__(self, bus_name, '/test/helloservice')

    def listen(self):
        loop = gobject.MainLoop()
        loop.run()

    @dbus.service.method('test.helloservice')
    def hello(self):
        return "Hello World!"


class BaseTestCase(unittest.TestCase):

    def setUp(self):
        env = os.environ.copy()
        self.p = subprocess.Popen(['python', './dbus_practice.py', 'server'], env=env)
        # Wait for the service to become available
        time.sleep(1)
        assert self.p.stdout == None
        assert self.p.stderr == None

    def testHelloService(self):
        bus = dbus.SessionBus()
        helloservice = bus.get_object('test.helloservice', '/test/helloservice')
        hello = helloservice.get_dbus_method('hello', 'test.helloservice')
        assert hello() == "Hello World!"

    def tearDown(self):
        # terminate() not supported in Python 2.5
        #self.p.terminate()
        os.kill(self.p.pid, 15)

if __name__ == '__main__':

    arg = ""
    if len(sys.argv) > 1:
        arg = sys.argv[1]

    if arg == "server":
        myservice = MyDBUSService()
        myservice.listen()

    else:
        unittest.main()

这篇关于如何为用Python编写的DBUS服务编写功能测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-26 12:35