如何通过D-Bus对等连接Mock ModemManager测试Go语言WWAN配置程序?
基于D-Bus对等连接Mock ModemManager的Go测试实现
1. 初始化D-Bus对等连接
通过创建双向管道搭建客户端(你的应用代码)与Mock服务器的直接通信,无需依赖系统D-Bus总线。用net.Pipe()生成双向管道,再通过godbus的NewConn初始化两端连接:
// 创建双向管道 clientConn, serverConn := net.Pipe() // 初始化客户端D-Bus连接 dbusClient, err := dbus.NewConn(clientConn) if err != nil { t.Fatal(err) } defer dbusClient.Close() // 初始化服务器端D-Bus连接 dbusServer, err := dbus.NewConn(serverConn) if err != nil { t.Fatal(err) } defer dbusServer.Close()
2. 实现Mock ModemManager服务
2.1 注册ModemManager服务名
在服务器端申请org.freedesktop.ModemManager1服务名,确保成为主所有者:
reply, err := dbusServer.RequestName("org.freedesktop.ModemManager1", dbus.NameFlagDoNotQueue) if err != nil { t.Fatal(err) } if reply != dbus.RequestNameReplyPrimaryOwner { t.Fatal("无法获取ModemManager服务名所有权") }
2.2 定义Mock对象与接口
根据ModemManager的D-Bus规范,创建结构体模拟核心接口的行为,比如模拟Simple.Connect和EnumerateModems方法:
// 模拟ModemManager主接口 type MockModemManager struct { t *testing.T } func (m *MockModemManager) EnumerateModems() ([]dbus.ObjectPath, *dbus.Error) { return []dbus.ObjectPath{"/org/freedesktop/ModemManager1/Modem/0"}, nil } // 模拟Modem的Simple接口 type MockModemSimple struct { t *testing.T } func (m *MockModemSimple) Connect(settings map[string]interface{}) (dbus.ObjectPath, *dbus.Error) { // 验证应用传入的配置参数 if apn, ok := settings["apn"]; !ok || apn != "test-apn" { m.t.Error("APN参数不符合预期") } // 返回模拟的Bearer对象路径 return dbus.ObjectPath("/org/freedesktop/ModemManager1/Bearer/0"), nil }
将Mock结构体注册到对应对象路径:
// 注册主服务对象与接口 err = dbusServer.Export(&MockModemManager{t: t}, "/org/freedesktop/ModemManager1", "org.freedesktop.ModemManager1") if err != nil { t.Fatal(err) } // 注册Modem对象与Simple接口 err = dbusServer.Export(&MockModemSimple{t: t}, "/org/freedesktop/ModemManager1/Modem/0", "org.freedesktop.ModemManager1.Modem.Simple") if err != nil { t.Fatal(err) }
3. 测试应用的WWAN配置逻辑
修改应用代码,支持传入自定义D-Bus连接(而非默认的系统总线),然后在测试用例中传入对等连接:
// 应用中的WWAN配置函数,支持自定义D-Bus连接 func ConfigureWWAN(conn *dbus.Conn, apn string) error { mmObj := conn.Object("org.freedesktop.ModemManager1", "/org/freedesktop/ModemManager1") // 枚举Modem var modems []dbus.ObjectPath err := mmObj.Call("org.freedesktop.ModemManager1.EnumerateModems", 0).Store(&modems) if err != nil { return err } if len(modems) == 0 { return fmt.Errorf("未找到Modem设备") } // 调用Simple.Connect接口 modemSimple := conn.Object("org.freedesktop.ModemManager1", modems[0]) _, err = modemSimple.Call("org.freedesktop.ModemManager1.Modem.Simple.Connect", 0, map[string]interface{}{ "apn": apn, }) return err } // 测试用例 func TestConfigureWWAN(t *testing.T) { // 初始化对等连接的代码... err := ConfigureWWAN(dbusClient, "test-apn") if err != nil { t.Fatal(err) } }
4. 模拟D-Bus信号(可选)
如果应用依赖ModemManager的信号(如ModemAdded),可在Mock服务器中主动发送信号:
// 发送ModemAdded信号 err = dbusServer.Emit("/org/freedesktop/ModemManager1", "org.freedesktop.ModemManager1.ModemAdded", dbus.ObjectPath("/org/freedesktop/ModemManager1/Modem/0")) if err != nil { t.Fatal(err) }
客户端需提前注册信号处理器,与生产环境逻辑一致即可。
注意事项
- 严格匹配ModemManager的D-Bus接口签名(参数、返回值类型),避免调用失败;
- 可在Mock方法中加入断言,验证应用传入的参数是否符合预期;
- 参考ModemManager官方D-Bus文档确认接口、信号的定义细节。
内容的提问来源于stack exchange,提问作者Kamil Zaripov
相关产品推荐
相关产品推荐

