簡體   English   中英

如何為用Python編寫的DBUS服務編寫功能測試?

[英]How to write a functional test for a DBUS service written in Python?

(標題是:“如何為用Python編寫的DBUS服務編寫單元測試?”)

我已經開始使用dbus-python編寫DBUS服務,但是我在編寫測試用例時遇到了麻煩。

這是我正在嘗試創建的測試示例。 請注意,我在setUp()中放置了一個GLib事件循環,這就是問題所在:

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()(雖然我沒有嫁給這種方法,如果有人有更好的建議)。 如果您沒有啟動事件循環,該服務仍會阻止,您也無法查詢它。

如果我在測試中啟動我的服務,事件循環會阻止測試完成。 我知道該服務正在運行,因為我可以使用qdbus工具從外部查詢服務,但我無法在啟動它的測試中自動執行此操作。

我正在考慮在測試中進行某種處理以處理這個問題,但我希望有人可能有一個更整潔的解決方案,或者至少是一個很好的起點,我將如何編寫這樣的測試。

在Ali A的帖子的幫助下,我設法解決了我的問題。 阻塞事件循環需要啟動到一個單獨的進程中,以便它可以在不阻塞測試的情況下偵聽事件。

請注意我的問題標題包含一些不正確的術語,我試圖編寫功能測試,而不是單元測試。 我知道這種區別,但直到后來才意識到我的錯誤。

我在我的問題中調整了這個例子。 它松散地類似於“test_pidavim.py”示例,但使用導入“dbus.glib”來處理glib循環依賴,而不是在所有DBusGMainLoop中編碼:

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()

簡單的解決方案:不要通過dbus進行單元測試。

而是編寫單元測試以直接調用您的方法。 這更符合單元測試的本質。

您可能還需要一些自動集成測試,它們檢查通過dbus運行,但它們不需要如此完整,也不需要單獨運行。 您可以在單獨的進程中進行設置以啟動服務器的實際實例。

我可能有點離開我的聯盟,因為我不知道python並且只知道這個神奇的“dbus”是什么,但如果我理解正確,它需要你用runloops創建一個相當不尋常的測試環境,擴展設置/拆卸,等等。

你的問題的答案是使用模擬 創建一個定義接口的抽象類,然后構建一個用於實際代碼的對象。 出於測試目的,您構建一個模擬對象通過相同的接口進行通信,但具有為測試目的定義的行為。 您可以使用此方法“模擬”通過事件循環運行的dbus對象,執行某些工作等,然后只關注測試您的類應該如何對該對象完成的“工作”結果做出反應。

您只需要確保正確處理主循環。

def refresh_ui():
    while gtk.events_pending():
       gtk.main_iteration_do(False)

這將運行gtk主循環,直到它完成處理所有內容,而不是僅運行它並阻止。

有關它在實踐中的完整示例,請對dbus接口進行單元測試,請訪問: http//pida.co.uk/trac/browser/pida/editors/vim/test_pidavim.py

你也可以在setUp方法中非常簡單地在一個單獨的線程中啟動mainloop。

像這樣的東西:

import threading
class BaseTestCase(unittest.TestCase):
    def setUp(self):
        myservice = MyDBUSService()
        self.loop = gobject.MainLoop()
        threading.Thread(name='glib mainloop', target=self.loop.run)
    def tearDown(self):
        self.loop.quit()

看看python-dbusmock庫。

它隱藏了丑陋的子進程邏輯,因此您不必在測試中擔心它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM