Vin*_*nie 67 unit-testing mocking dart
我喜欢在我的Dart应用程序中模拟异步Web服务调用以进行测试.为了模拟这些模拟调用响应的随机性(可能是乱序),我想编程我的模拟等待(睡眠)一段时间后再返回'Future'.
我怎样才能做到这一点?
Tim*_*mmm 148
2019版:
await Future.delayed(Duration(seconds: 1));
Run Code Online (Sandbox Code Playgroud)
import 'dart:io';
sleep(Duration(seconds:1));
Run Code Online (Sandbox Code Playgroud)
注意:这会阻塞整个进程(隔离),因此不会处理其他异步函数。它也无法在网络上使用,因为 Javascript 实际上是仅异步的。
Sha*_*uli 76
您还可以使用Future.delayed工厂在延迟后完成未来.以下是两个在延迟后异步返回字符串的函数的示例:
import 'dart:async';
Future sleep1() {
return new Future.delayed(const Duration(seconds: 1), () => "1");
}
Future sleep2() {
return new Future.delayed(const Duration(seconds: 2), () => "2");
}
Run Code Online (Sandbox Code Playgroud)
Set*_*add 42
它并不总是你想要的(有时你想要的Future.delayed),但是如果你真的想睡在你的Dart命令行应用程序中,你可以使用dart:io sleep():
import 'dart:io';
main() {
sleep(const Duration(seconds:1));
}
Run Code Online (Sandbox Code Playgroud)
Spk*_*ngR 16
我发现Dart中有几种实现可以使代码延迟执行:
new Future.delayed(const Duration(seconds: 1)); //recommend
new Timer(const Duration(seconds: 1), ()=>print("1 second later."));
sleep(const Duration(seconds: 1)); //import 'dart:io';
new Stream.periodic(const Duration(seconds: 1), (_) => print("1 second later.")).first.then((_)=>print("Also 1 second later."));
//new Stream.periodic(const Duration(seconds: 1)).first.then((_)=>print("Also 1 second later."));
Run Code Online (Sandbox Code Playgroud)
小智 14
对于Dart 2+语法,在异步函数上下文中:
import 'package:meta/meta.dart'; //for @required annotation
void main() async {
void justWait({@required int numberOfSeconds}) async {
await Future.delayed(Duration(seconds: numberOfSeconds));
}
await justWait(numberOfSeconds: 5);
}
Run Code Online (Sandbox Code Playgroud)
Mar*_* Ge 11
由于最佳答案的编辑队列已满,这里是该问题的最新工作改编:
await Future<void>.delayed(const Duration(seconds: 1));
Run Code Online (Sandbox Code Playgroud)
import 'dart:io';
sleep(const Duration(minutes: 1));
Run Code Online (Sandbox Code Playgroud)
注意:这会阻塞整个进程(隔离),因此其他异步函数将不会被处理。它在网络上也不可用,因为 Javascript 实际上是异步的。
Dart 在单个进程或线程(即事件循环)中运行所有代码。因此async,实际上,块/方法中的代码也在某种类型和顺序的“全局”序列中运行,以馈送事件循环。换句话说:Dart 中没有,只有一个“线程”(暂时不包括 Isolates,见下文)。
当必须模仿随着时间的推移到达的数据sleep(例如通过流)时,可能会遇到在块/方法中运行的代码中使用的陷阱async。思考:“我的代码触发一个新线程并愉快地继续前进,并在 UI 层和所有内容上保持响应! ”。但事实并非如此:在 Dart 中,你只是射中了自己的膝盖。
当在任何地方使用时sleep,而不仅仅是在异步代码中,这将停止“唯一”事件循环,并且每个“线程”都被阻塞,即所有代码,所有内容......(......因为实际上没有“线程” “就像 Java 中的例子)。
注意:最重要的是,UI 将阻塞,不会重新绘制,并且不会响应任何输入。期间发生的所有幕后事件sleep,只有在“醒来”之后才会变得可见。
举个例子,考虑一个将项目附加到自身的列表(可能通过流/StreamBuilder)。在“真实的应用程序生活”中,数据通常来自“外部源”,它以延迟的、不可预测的方式发送数据。所以,一切都好……
...但是,当从代码中模仿数据时,例如通过按钮事件,涉及sleep同步或异步,并不重要,列表只会在最后所有睡眠结束时重新绘制。此外,任何其他按钮事件(例如)在此之后也不会由事件循环调度。
考虑这段代码:
不
Future<VoidCallback?> asyncWithSleep() async {
print('start');
for (var i = 0; i < 5; i++) {
sleep(const Duration(seconds: 1));
print(i);
}
print('end');
return null;
}
Run Code Online (Sandbox Code Playgroud)
印刷:
flutter: start
flutter: 0
flutter: 1
flutter: 2
flutter: end
Run Code Online (Sandbox Code Playgroud)
如果您期望 end 会在数字之前打印,那么现在大声说出来:“sleep在 Dart 中导致所有线程等待”。基本上,除非您从上到下运行命令行脚本,或者在隔离中运行代码,否则请忘记sleep.
例如,为了模拟来自 Web 服务、数据库或底层平台等来源的数据,您可以Future.delayed为您想要模拟的每条数据生成一个 。
做
void syncWithDelayedFutureAndNoSyncDownTheLine() { // doesn't have to be async but could, if Future setup takes too long
print('start');
for (var i = 0; i < 3; i++) {
Future.delayed(const Duration(seconds: i + 1), () {
print(i);
});
}
print('end');
return null;
}
Run Code Online (Sandbox Code Playgroud)
这不会阻塞 UI 或其他任何东西。它设置了三个将来异步运行的代码块,分别在 1、2 和 3 秒内到达 for 循环。
印刷:
flutter: start
flutter: end
flutter: 0
flutter: 1
flutter: 2
Run Code Online (Sandbox Code Playgroud)
(如果每秒模拟的数据看起来太无聊,请在参数的 Duration 参数中添加一些摆动和随机性Future.delayed......)
创建用于模拟或测试的未来事件的关键是正确设置未来的持续时间。异步代码中的阻塞无法按预期工作,因为它会阻塞所有代码。
如果您仍然认为需要sleep在程序中的任何地方使用,请查看Dart 的Isolates. 我还没有使用过它们,但从我所看到的来看,它们对我来说有点像 Java 线程,没有共享内存的负担,而且有很多陷阱。然而,它们的目的是作为“后台工作人员”,用于计算/时间密集型处理,当从相同的主隔离main()运行时,这可能会使程序的其余部分变得缓慢。
这是一个有用的模拟,可以使用可选参数来模拟错误:
Future _mockService([dynamic error]) {
return new Future.delayed(const Duration(seconds: 2), () {
if (error != null) {
throw error;
}
});
}
Run Code Online (Sandbox Code Playgroud)
你可以这样使用它:
await _mockService(new Exception('network error'));
Run Code Online (Sandbox Code Playgroud)