Pythonで書かれたDBUSサービスの機能テストを書くためにどのように?
-
21-08-2019 - |
質問
(タイトルだった:「?どのようにPythonで書かれてDBUSサービスのためのユニットテストを書くこと」)
私はdbusの-のpythonを使用してDBUSサービスを書き始めましたが、私はそれのためのテストケースを書く問題を抱えています。
ここで私が作成しようとしていますテストの例です。私はセットアップで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を使用します(誰かがより良い提案を持っている場合、私は、このアプローチに結婚していないんだが)。)(開始することです。あなたがイベントループ、サービスがまだブロックを開始しませんし、あなたもそれを照会することができない場合ます。
私はテストで私のサービスを開始した場合、イベントループブロックの完成からテスト。私はqdbusツールを使用して、外部サービスを照会することができるため、サービスが動作しているけど、私はそれを開始し、テスト内でこれを自動化することはできません。
私はこれを処理するために、テスト内のフォークプロセスのいくつかの種類をやって検討しているが、私は誰かがすっきり解決策、またはどのように私はこのようなテストを書くとするための、少なくとも良い出発場所を持っているかもしれません期待していました。
解決
アリAの記事からいくつかの助けを借りて、私は私の問題を解決するために管理しています。それはテストをブロックせずにイベントをリッスンできるように、ブロッキングイベントループは、独立したプロセスに起動する必要がありました。
ユニットテストとは対照的に、私は、機能テストを書くためにしようとしていた、私の質問のタイトルがいくつか間違った用語が含まれていますのでご注意ください。私は違いを知っていたが、後になるまで私のミスを実現しませんでした。
私は私の質問の例を調整してきました。それは緩く「test_pidavim.py」の例に似ているが、すべてのDBusGMainLoopのものでコーディングするのではなく、glibのループの依存関係を処理するために、「dbus.glib」のインポートを使用します:
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を走るチェックし、いくつかの自動化された統合テストを、お勧めしますが、彼らはそう完全にする必要があり、また単独では実行されません。あなたは別のプロセスで、あなたのサーバの実際のインスタンスを起動し、セットアップを持つことができます。
私は、ここに私のリーグのうち、少しかもしれないが、私が正しく理解すれば、それはではなく、異常なテスト環境を作成する必要がありますrunloops、拡張セットアップ/ティアダウンなど。
あなたの問題への答えはモックを使用することです。あなたのインターフェースを定義する抽象クラスを作成し、あなたの実際のコードで使用することからオブジェクトを構築します。テストの目的のために、あなたはモックオブジェクトを構築し、その同じインターフェイスを介して通信しますが、の振る舞いを持っています。は、テストの目的のために定義します。あなたは、など、いくつかの仕事をして、イベントループを実行しているdbusのオブジェクトを「シミュレート」するために、このアプローチを使用して、簡単にどのようにあなたのクラスは、そのオブジェクトによって行われ、「仕事」の結果に反応するはずのテストに集中することができます。
あなたはちょうどあなたがあなたのメインループを適切に処理していることを確認する必要があります。
def refresh_ui():
while gtk.events_pending():
gtk.main_iteration_do(False)
それはちょうどそれとブロックを実行するのではなく、すべての処理を完了するまで。 これはGTKのメインループを実行します
実際には、それの完全な例については、単位dbusのインターフェイスをテストし、ここに行く:<のhref =「http://pida.co.uk/trac/browser/pida/editors/vim/test_pidavim.py」 rel = "nofollowをさnoreferrer"> http://pida.co.uk/trac/browser/pida/editors/vim/test_pidavim.py の
また、あなたのセットアップ方法の内側に非常に簡単に別のスレッドでメインループを開始することができます。
このような何かます:
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 のライブラリをチェックしてください。
あなたのテストでそれを心配する必要はありませんので、これは、あなたの目の後ろに醜いサブプロセス・ロジックを隠します。