我有一个密码

var i = 0;
_searchService.FindAll()
    .SubscribeOn(NewThreadScheduler.Default)
    .Subscribe(i => { i++ }, () => { i *= 2; });


据我所知,应用.SubscribeOn(NewThreadScheduler.Default)使IObserver在新线程中运行。一切正常,但我对单元测试有疑问。

我进行了必要的更改,但此订阅运行在另一个框架中不再等待。如何取消.SubscribeOn(NewThreadScheduler.Default)进行单元测试。如果不进行此任命,代码将运行良好。

我已经尝试了反应式UI testScheduler.With(((scheduler)=> {...在此处编写此代码...});但没有成功。我怎么解决这个问题?

最佳答案

您将要使用TestScheduler代替NewThreadScheduler进行单元测试。我假设您使用IoC作为设计模式来启用您的单元测试,因此您所需要做的就是创建一个ISchedulerProvider / ISchedulerService / ...接口,以暴露您的需求。这是我用的东西

public interface ISchedulerProvider
{
    /// <summary>
    /// Provides access to scheduling onto the UI Dispatcher.
    /// </summary>
    IScheduler Dispatcher { get; }

    /// <summary>
    /// Provides concurrent scheduling. Will use the thread pool or the task pool if available.
    /// </summary>
    IScheduler Concurrent { get; }

    /// <summary>
    /// Provides concurrent scheduling for starting long running tasks. Will use a new thread or a long running task if available. Can be used to run loops more efficiently than using recursive scheduling.
    /// </summary>
    ISchedulerLongRunning LongRunning { get; }

    /// <summary>
    /// Provides support for scheduling periodic tasks. Can be used to run timers more efficiently than using recursive scheduling.
    /// </summary>
    ISchedulerPeriodic Periodic { get; }
}

public sealed class SchedulerProvider : ISchedulerProvider
{
    private readonly IScheduler _dispatcherScheduler;

    public SchedulerProvider()
    {
        var currentDispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
        _dispatcherScheduler = new DispatcherScheduler(currentDispatcher);
    }

    public IScheduler Dispatcher
    {
        get { return _dispatcherScheduler; }
    }


    public IScheduler Concurrent
    {
        get { return TaskPoolScheduler.Default; }
    }

    public ISchedulerLongRunning LongRunning
    {
        get { return TaskPoolScheduler.Default.AsLongRunning(); }
    }

    public ISchedulerPeriodic Periodic
    {
        get { return TaskPoolScheduler.Default.AsPeriodic(); }
    }
}


然后,在测试中,您将使用一个返回TestScheduler实现的实现。

public sealed class TestSchedulerProvider : ISchedulerProvider
{
    private readonly TestScheduler _dispatcher = new TestScheduler();
    private readonly TestScheduler _concurrent = new TestScheduler();
    private readonly TestScheduler _longRunning = new TestScheduler();
    private readonly TestScheduler _periodic = new TestScheduler();


    IScheduler ISchedulerProvider.Dispatcher
    {
        get { return _dispatcher; }
    }
    public TestScheduler Dispatcher
    {
        get { return _dispatcher; }
    }

    IScheduler ISchedulerProvider.Concurrent
    {
        get { return _concurrent; }
    }
    public TestScheduler Concurrent
    {
        get { return _concurrent; }
    }

    ISchedulerLongRunning ISchedulerProvider.LongRunning
    {
        get { return _longRunning.AsLongRunning(); }
    }
    public TestScheduler LongRunning
    {
        get { return _longRunning; }
    }

    ISchedulerPeriodic ISchedulerProvider.Periodic
    {
        get { return _periodic.AsPeriodic(); }
    }
    public TestScheduler Periodic
    {
        get { return _periodic; }
    }
}


如您所见,这是针对WPF项目的,但是您可以根据需要进行更改(删除或添加)。

我尝试在我的网站http://introtorx.com/Content/v1.0.10621.0/16_TestingRx.html上详细解释如何使用TestScheduler测试Rx

我不太了解您的示例代码在做什么,但我认为您可能想将其更新为

var testScheduler = new TestScheduler();
var i = 0;
var subscription = _searchService
              .FindAll()
              .SubscribeOn(testScheduler)
              .Subscribe(
                 i =>i++,
                 () => i*=2);
Assert.AreEqual(0, i);
testScheduler.AdvanceBy(1);
Assert.AreEqual(1, i);
subscription.Dispose();

10-06 11:24