2

我有几种不同“类型”的传入事件,我想将它们分派给不同的 IObservable,作为属性公开,但无需多次订阅底层 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; }
4

2 回答 2

2

我认为问题在于:

subject.OnNext(spaceEvent);
var result = dispatcher.SpaceEventChannel.SingleOrDefault();

尝试将其替换为:

AbstractEvent result = null;
dispatcher.SpaceEventChannels.Subscribe(e => result = e);
subject.OnNext(spaceEvent);
// ...

问题是,当您调用 subject.OnNext 时,它会立即通过“管道”* *运行。因此,下一行的 SingleOrDefault 实际上锁定了文本,因为没有任何值“到达”它。

于 2012-05-09T07:35:16.740 回答
0

您遇到的主要问题很简单。这一行:

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如果这就是它真正需要的。你可以想象这也将是多么容易测试!

于 2012-05-09T07:00:51.217 回答