【问题标题】:Unit testing actix actors, sending messages to different types of actor单元测试actix actor,向不同类型的actor发送消息
【发布时间】:2021-11-22 22:47:59
【问题描述】:

我正在尝试使用 Rust Actix Actor 框架,其中有一个线程轮询一些硬件,形成简单的事件消息并通过其 Addr 将它们发送到 Actor。有一个枚举 KeyingEvent 构成 Message

在我的测试中,我有一个 Actor 捕获传入的 KeyingEvents,并记录它们以供测试验证:

    struct CapturingKeyingEventReceiver {
        received_keying_events: Vec<KeyingEvent>,
    }
    impl CapturingKeyingEventReceiver {
        fn new() -> Self {
            Self {
                received_keying_events: vec![],
            }
        }
    }
    impl Actor for CapturingKeyingEventReceiver {
        type Context = Context<Self>;
    }
    impl Handler<KeyingEvent> for CapturingKeyingEventReceiver {
        type Result = ();
        fn handle(&mut self, keying_event: KeyingEvent, _ctx: &mut Self::Context) {
            info!("Keying Event {}", keying_event);
            self.received_keying_events.push(keying_event);
        }
    }

我开始这个并得到它的地址:

let capturing_keying_event_receiver = CapturingKeyingEventReceiver::new().start();

这是一个 Addr,我可以将它传递给我的线程代码的构造函数....

但是在我的应用程序代码中,我有一个不同的 Actor,KeyingEventRouter,它也处理这些消息并将它们路由到各种其他子系统:

struct KeyingEventRouter {
...
}
impl Actor for KeyingEventRouter {
...
}
impl Handler<KeyingEvent> for KeyingEventRouter {
...
}

我遇到的问题是在我的线程代码构造函数中,我如何传递一个通用的Addr&lt;???&gt; 作为线程应该向其发送消息的目标actor? - 我尝试将构造函数中的参数指定为:

pub fn new(keying_event_receiver: Addr<dyn Actor>) -> Self {
...

但 Rust 不允许这样做:

help: specify the associated type: `Actor<Context = Type>`

我希望它能够将这些消息发送给Handler&lt;KeyingEvent&gt; 的任何参与者。如何让构造函数在我的测试中使用Addr&lt;CapturingKeyingEventReceiver&gt;,在我的应用程序代码中使用Addr&lt;KeyingEventRouter&gt;

在 Java 中(有点手忙脚乱)我会创建一个接口 KeyingEventReceiver,让 CapturingKeyingEventReceiverKeyingEventRouter 继承它,并传递一个 Addr&lt;KeyingEventReceiver&gt;..... 但是你怎么说'impl来自 KeyingEventReceiver 的 Actor,因为 KeyingEventReceiver 必须是一个具体的结构?

【问题讨论】:

  • 我仍然对此问题的解决方案感兴趣,以进一步了解使用 Rust 的设计/限制。我找到了一种方法来实现我的手动 Java 方法的想法 - 如果你有一个 Actor&lt;CapturingKeyingEventReceiver&gt;,你可以获得它的 Addr&lt;CapturingKeyingEventReceiver&gt;,然后调用 recipient() 函数。这会给你一个Recipient&lt;KeyingEvent&gt;,这将是我的测试和生产代码中的相同类型。即使使用上述方法,我也无法让我的代码与 Actix 一起使用;文档非常稀少,所以正在尝试 Riker。

标签: rust rust-actix


【解决方案1】:

您正在寻找Recipient

你需要这样做:

let addr = CapturingKeyingEventReceiver::new().start();

/// https://docs.rs/actix/0.12.0/src/actix/address/mod.rs.html#142-150
let keying_event_receiver = addr.recipient();

pub fn new(keying_event_receiver: Recipient<KeyingEvent>) -> Self {
    keying_event_receiver.send(...)

您还可以在 actix crate 上查看这些测试:https://docs.rs/actix/0.12.0/src/actix/address/mod.rs.html#401

【讨论】:

  • 谢谢你,恩朱古纳。这会奏效;如果我在其他项目中重新访问 Actix,我将使用这种方法。从那以后,我更改了架构以使用总线板条箱,并在系统中的各种线程对象之间仔细共享数据 - 我相信在我的情况下,Actix 演员中状态的紧密封装不会很好地工作。
猜你喜欢
  • 2021-09-11
  • 2015-05-29
  • 2013-04-30
  • 2019-10-17
  • 2017-06-29
  • 1970-01-01
  • 1970-01-01
  • 2017-03-10
  • 1970-01-01
相关资源
最近更新 更多