gpt4 book ai didi

c# - ReactiveUI 中的 TestScheduler 异步方法死锁

转载 作者:可可西里 更新时间:2023-11-01 08:28:28 27 4
gpt4 key购买 nike

我正在尝试在测试中使用带有异步方法的 reactiveui 测试调度程序。

等待异步调用时测试挂起。

根本原因似乎是在异步方法中等待的命令。

    [Fact]
public async Task Test()
=> await new TestScheduler().With(async scheduler =>
{
await SomeAsyncMethod();

// *** execution never gets here
Debugger.Break();
});

private async Task SomeAsyncMethod()
{
var command = ReactiveCommand.CreateFromTask(async () =>
{
await Task.Delay(100);
});

// *** this hangs
await command.Execute();
}

如何结合不会死锁的测试调度程序进行异步调用?

我正在使用 reactiveui 9.4.1

编辑:

我已经按照 Funks 回答中的建议尝试了 WithAsync() 方法,但行为是一样的。

最佳答案

How can I do an async call in combination with the test scheduler?

简而言之

command.Execute() 是一个冷可观察对象。您需要订阅它,而不是使用 await

鉴于您对 TestScheduler 的兴趣,我认为您想要测试涉及时间的东西。然而,从When should I care about scheduling部分:

threads created via "new Thread()" or "Task.Run" can't be controlled in a unit test.

因此,如果您想要检查,例如,您的 Task 是否在 100 毫秒内完成,您将不得不等待异步方法完成。可以肯定的是,不是 TestScheduler 的测试类型。

稍长的版本

TestScheduler 的目的是通过在特定时间点启动事物并验证状态来验证工作流。由于我们只能在 TestScheduler 上操纵时间,因此您通常不希望等待真正的异步代码完成,因为没有办法快进实际计算或 I/O。请记住,这是关于验证工作流:vm.A 在 20ms 时有新值,所以 vm.B 应该在 120ms 时有新值,...

那么如何测试 SUT?

1\您可以使用 scheduler.CreateColdObservable

模拟异步方法
public class ViewModelTests
{
[Fact]
public void Test()
{
string observed = "";

new TestScheduler().With(scheduler =>
{
var observable = scheduler.CreateColdObservable(
scheduler.OnNextAt(100, "Done"));

observable.Subscribe(value => observed = value);
Assert.Equal("", observed);

scheduler.AdvanceByMs(99);
Assert.Equal("", observed);

scheduler.AdvanceByMs(1);
Assert.Equal("Done", observed);
});
}
}

在这里,我们基本上用 scheduler 上创建的 var observable 替换了 command.Execute()

很明显,上面的示例相当简单,但是通过多个可观察对象相互通知,这种测试可以提供有值(value)的见解,以及重构时的安全网。

引用:

2\您可以显式引用IScheduler

a) 使用 RxApp 提供的调度程序

public class MyViewModel : ReactiveObject
{
public string Observed { get; set; }

public MyViewModel()
{
Observed = "";

this.MyCommand = ReactiveCommand
.CreateFromTask(SomeAsyncMethod);
}

public ReactiveCommand<Unit, Unit> MyCommand { get; }

private async Task SomeAsyncMethod()
{
await RxApp.TaskpoolScheduler.Sleep(TimeSpan.FromMilliseconds(100));
Observed = "Done";
}
}

public class ViewModelTests
{
[Fact]
public void Test()
{
new TestScheduler().With(scheduler =>
{
var vm = new MyViewModel();

vm.MyCommand.Execute().Subscribe();
Assert.Equal("", vm.Observed);

scheduler.AdvanceByMs(99);
Assert.Equal("", vm.Observed);

scheduler.AdvanceByMs(1);
Assert.Equal("Done", vm.Observed);
});
}
}

注意

  • CreateFromTask 创建一个具有异步执行逻辑的 ReactiveCommand。无需将 Test 方法定义为异步或等待 TestScheduler

  • With 扩展方法的范围内 RxApp.TaskpoolScheduler = RxApp.MainThreadScheduler = new TestScheduler().

b) 通过构造函数注入(inject)管理你自己的调度器

public class MyViewModel : ReactiveObject
{
private readonly IScheduler _taskpoolScheduler;
public string Observed { get; set; }

public MyViewModel(IScheduler scheduler)
{
_taskpoolScheduler = scheduler;
Observed = "";

this.MyCommand = ReactiveCommand
.CreateFromTask(SomeAsyncMethod);
}

public ReactiveCommand<Unit, Unit> MyCommand { get; }

private async Task SomeAsyncMethod()
{
await _taskpoolScheduler.Sleep(TimeSpan.FromMilliseconds(100));
Observed = "Done";
}
}

public class ViewModelTests
{
[Fact]
public void Test()
{
new TestScheduler().With(scheduler =>
{
var vm = new MyViewModel(scheduler); ;

vm.MyCommand.Execute().Subscribe();
Assert.Equal("", vm.Observed);

scheduler.AdvanceByMs(99);
Assert.Equal("", vm.Observed);

scheduler.AdvanceByMs(0);
Assert.Equal("Done", vm.Observed);
});
}
}

引用:

让我们用来自 Haacked 的另一句话来拉近距离:

Unfortunately, and this next point is important, the TestScheduler doesn’t extend into real life, so your shenanigans are limited to your asynchronous Reactive code. Thus, if you call Thread.Sleep(1000) in your test, that thread will really be blocked for a second. But as far as the test scheduler is concerned, no time has passed.

关于c# - ReactiveUI 中的 TestScheduler 异步方法死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53728846/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com