【问题标题】:Unit test IObservable<T> with ObserveOnDispatcher使用 ObserveOnDispatcher 对 IObservable<T> 进行单元测试
【发布时间】:2012-07-04 15:16:13
【问题描述】:

我需要测试一段代码

        var watcher = new FakeIFileSystemWatcher();
        watcher.FilesToBeImported
            .ObserveOnDispatcher()
            .Subscribe(list.Add);

所以我创建了这个小单元测试,但我不能让它通过因为 list.Count 总是 0

    [Test]
    public void Foo()
    {
        var list = new List<string>();

        var watcher = new FakeIFileSystemWatcher();
        watcher.FilesToBeImported
            .ObserveOnDispatcher()
            .Subscribe(list.Add);

        Task task = Task.Factory.StartNew(() =>
        {                
            watcher.AddFile("cc");
            watcher.AddFile("cc");
            watcher.AddFile("cc");
        }, TaskCreationOptions.LongRunning);
        Task.WaitAll(task);

        Assert.AreEqual(3, list.Count);
    }

如果我注释掉方法

            .ObserveOnDispatcher()

它通过了,但我怎样才能让它与 ObserveOnDispatcher() 一起工作?

【问题讨论】:

  • 失败时list.Count的值是多少?
  • 我使用我在这里找到的类 DispatcherUtil 解决了stackoverflow.com/questions/1106881/…
  • 我只想指出,通过在单元测试中使用并发(隐式或显式),您的能力确实受到了限制。在这里,您有 Tasks 和 Dispatcher,您没有提供任何“接缝”,您可以在其中将它们替换为测试替身(模拟/存根)。就像(我假设)您在产品代码中注入 IFileSystemWatcher 的真实实现一样,您将注入一个 SchedulerProvider,它在产品中为您提供真正的并发,但在您的单元测试中测试调度程序。更快的单元测试,更容易测试超时等其他事情。

标签: c# linq reactiveui


【解决方案1】:

如果您使用ObserveOnDispatcher,您将创建对“调度程序”的依赖,这意味着您需要一个窗口和一个消息循环。要在单元测试中解决此问题,您可以改用 ObserveOn 方法,该方法使用调度程序,然后使用依赖注入来注入正确的调度程序。对于单元测试,您可以使用Scheduler.Immediate,对于实际应用程序,您可以使用DispatcherScheduler.Instance。请注意,还有一个TestScheduler,它对于在虚拟时间运行单元测试非常有用。

【讨论】:

  • 感谢您的回复。这行代码 watcher.FilesToBeImported.ObserveOnDispatcher().Subscribe(list.Add);正在我的系统中进行测试,所以我不能仅仅为了测试而改变它
  • @scott4dev:我的意思是,有时您必须修改被测系统以使其可单元测试。例如。如果您访问数据库,则必须为数据库创建一个接口,允许您对数据库访问等进行存根。您的解决方案当然会避免这种情况。
  • 您是对的,有时必须修改您的被测系统以使其可单元测试,但在我看来并非如此。我更喜欢使用 DispatcherUtil.DoEvents();在我的测试中,让我的 SUT 处于原始状态
【解决方案2】:

我使用我在这里找到的类 DispatcherUtil 解决了 Using the WPF Dispatcher in unit tests

现在我的代码如下

    [Test]
    public void Foo()
    {
        var list = new List<string>();

        var watcher = new FakeIFileSystemWatcher();
        watcher.FilesToBeImported
            .ObserveOnDispatcher()
            .Subscribe(list.Add);

        Task task = Task.Factory.StartNew(() =>
        {
            watcher.AddFile("cc");
            watcher.AddFile("cc");
            watcher.AddFile("cc");
            watcher.AddFile("cc");
        }, TaskCreationOptions.LongRunning);
        Task.WaitAll(task);
        DispatcherUtil.DoEvents();
        Assert.AreEqual(4, list.Count);
    }

它就像一个魅力

【讨论】:

    【解决方案3】:

    您可以尝试像这样调用您的方法:

    var dispatcher = Application.Current != null ? Application.Current.Dispatcher : Dispatcher.CurrentDispatcher;
    
     dispatcher.Invoke((Action)(() => YourMethodToTest());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-31
      • 2017-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-08
      • 1970-01-01
      相关资源
      最近更新 更多