测试 IObservable “调度程序”
本文关键字:调度程序 IObservable 测试 | 更新日期: 2023-09-27 18:33:30
我有几种不同的传入事件'类型',我想将它们调度到不同的IObservables,作为属性公开,但不多次订阅底层UDP。
public IObservable<TimeEvent> TimeEventChannel { get; private set; }
public IObservable<SpaceEvent> SpaceEventChannel { get; private set; }
Subject<TimeEvent> _TimeSubject = new Subject<TimeEvent>();
Subject<SpaceEvent> _SpaceSubject = new Subject<SpaceEvent>();
public EventDispatcher(IChannelListener listener)
{
TimeEventChannel = _TimeSubject;
SpaceEventChannel = _SpaceSubject;
listener.Data.Subscribe(SwitchEvent);
}
private void SwitchEvent(AbstractEvent e)
{
switch(e.EventType)
{
case EEventType.Time: _TimeSubject.OnNext(e as TimeEvent); break;
case EEventType.Space: _SpaceSubject.OnNext(e as SpaceEvent); break;
}
}
(listener.Data
是一个IObservable<AbstractEvent>
)。
我遇到的问题是试图弄清楚如何单独测试它(不连接到 UDP)
var spaceEvent = new SpaceEvent();
var udpSubject = new Subject<AbstractEvent>();
var mock = new Mock<IChannelListener>();
mock.SetupGet(listener => listener.Data).Returns(udpSubject);
var dispatcher = new EventDispatcher(mock.Object);
subject.OnNext(spaceEvent);
var result = dispatcher.SpaceEventChannel.SingleOrDefault();
就目前而言,测试块在最后一行,我很确定这是因为我从根本上没有摸索Subject
如何工作。
问:我怎么想错了?我应该如何测试这个特定的用例?我也在向后实现调度程序吗?
以防万一,这是目前真正的ChannelListener
的样子:
public ChannelListener(UdpClient udpClient, FrameInterpreter frameInterpreter)
{
Data = Observable.Defer(() =>
{
IPEndPoint ep = null;
return Observable.FromAsyncPattern<byte[]>(
udpClient.BeginReceive,
i => udpClient.EndReceive(i, ref ep)
)()
.Select(bytes => frameInterpreter.ParseFrame(bytes));
});
}
public IObservable<AbstractEvent> Data { get; private set; }
我认为问题出在以下几行:
subject.OnNext(spaceEvent);
var result = dispatcher.SpaceEventChannel.SingleOrDefault();
尝试将其替换为:
AbstractEvent result = null;
dispatcher.SpaceEventChannels.Subscribe(e => result = e);
subject.OnNext(spaceEvent);
// ...
问题是当你称呼主题时。在下一个,它立即通过"管道"*运行。因此,下一行的 SingleOrDefault 实际上锁定了文本,因为没有任何值"到达"到它。
您遇到的主要问题很简单。这一行:
listener.Data.Subscribe(SwitchEvent);
返回一个IDisposable
。立即超出范围并被处置。所以SwitchEvent
永远不会开火。您只需将该IDisposable
保存在 EventDispatcher
类的实例变量中。
private IDisposable _subscription;
public EventDispatcher(IChannelListener listener)
{
TimeEventChannel = _TimeSubject;
SpaceEventChannel = _SpaceSubject;
_subscription = listener.Data.Subscribe(SwitchEvent);
}
我也会认真考虑改变EventDispatcher
以接受IObservable<AbstractEvent>
而不是IChannelListener
,如果这是它真正需要的。您可以想象这也更容易测试!