我如何测试实际发生的转换
how do I test for a transition actually occuring
给定一个在 Stream 事件中“摇晃”的小部件
class Shaker extends StatefulWidget {
final Widget child;
final Stream<void> stream;
final Duration duration;
final int loops;
const Shaker({
required this.child,
required this.stream,
this.duration = const Duration(milliseconds: 100),
this.loops = 2,
Key? key,
}) : super(key: key);
@override
State<Shaker> createState() => _ShakerState();
}
class _ShakerState extends State<Shaker> with SingleTickerProviderStateMixin {
late final AnimationController _controller;
late final StreamSubscription _subscription;
late final Animation<Offset> _offsetAnimation;
@override
void initState() {
_controller = AnimationController(
vsync: this,
duration: widget.duration,
);
_subscription = widget.stream.listen((event) async {
for (var i = 0; i < widget.loops; ++i) {
await _controller.forward();
await _controller.reverse();
}
});
_offsetAnimation = Tween<Offset>(
begin: Offset.zero,
end: const Offset(.02, 0.0),
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.elasticIn,
));
super.initState();
}
@override
void dispose() {
_controller.dispose();
_subscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SlideTransition(
position: _offsetAnimation,
child: widget.child,
);
}
}
什么是测试事件接收到的“抖动”实际发生的优雅方法?
谢谢
在您的小部件测试中,您可以使用 WidgetTester.pump()
和 WidgetTester.pumpAndSettle()
来验证此行为。
pump()
只是从框架渲染一个新帧,但是 pumpAndSettle()
连续渲染帧直到没有更多的预定帧,然后 returning 预定的帧数.
一个简单(但不太精确)的测试是确保您的动画播放正确的帧数。类似于:
const expectedFramesForShake = 10;
testWidgets('example', (tester) async {
final controller = StreamController<void>();
await tester.pumpWidget(Shaker(stream: controller.stream, /* other fields */));
controller.add(null); // cause a shake
final frames = await tester.pumpAndSettle();
expect(frames, expectedFramesForShake);
});
请注意,您可能必须将小部件包装在 MaterialApp
中以设置必要的 InheritedWidget
以通过测试。
这验证了动画播放的时间大致正确,但我们可以做得更好!
与其依赖 pumpAndSettle()
到 return 计划的帧数,我们可以在每一帧之后检查小部件树。
// change this so it matches the values produced by the "correct" animation
const expectedOffsets = [0.0, 1.0, 3.0, 7.0,];
testWidgets('better example', (tester) async {
final controller = StreamController<void>();
await tester.pumpWidget(Shaker(stream: controller.stream, /* other fields */));
final offsets = <double>[]; // empty list to store results
controller.add(null);
do {
// pull the SlideTransition from the widget tree
final transition = tester.widget<SlideTransition>(find.byType<SlideTransition>);
// read the current value of the position animation
final horizontalOffset = transition.position.value.dx;
offsets.add(horizontalOffset);
// now request a new frame
await tester.pump();
// only loop while there are more frames scheduled
} while (tester.binding.hasScheduledFrame);
// compare the 2 arrays
expect(offsets, expectedOffsets);
});
这使您可以确定 Shaker
正在为每个帧偏移其子项的正确量。但是,这会使您的测试非常脆弱,例如,如果您想更改摇晃的持续时间,它将更改 offsets
.
的值
P.S。感谢 dartpad 示例 :-)
给定一个在 Stream 事件中“摇晃”的小部件
class Shaker extends StatefulWidget {
final Widget child;
final Stream<void> stream;
final Duration duration;
final int loops;
const Shaker({
required this.child,
required this.stream,
this.duration = const Duration(milliseconds: 100),
this.loops = 2,
Key? key,
}) : super(key: key);
@override
State<Shaker> createState() => _ShakerState();
}
class _ShakerState extends State<Shaker> with SingleTickerProviderStateMixin {
late final AnimationController _controller;
late final StreamSubscription _subscription;
late final Animation<Offset> _offsetAnimation;
@override
void initState() {
_controller = AnimationController(
vsync: this,
duration: widget.duration,
);
_subscription = widget.stream.listen((event) async {
for (var i = 0; i < widget.loops; ++i) {
await _controller.forward();
await _controller.reverse();
}
});
_offsetAnimation = Tween<Offset>(
begin: Offset.zero,
end: const Offset(.02, 0.0),
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.elasticIn,
));
super.initState();
}
@override
void dispose() {
_controller.dispose();
_subscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SlideTransition(
position: _offsetAnimation,
child: widget.child,
);
}
}
什么是测试事件接收到的“抖动”实际发生的优雅方法?
谢谢
在您的小部件测试中,您可以使用 WidgetTester.pump()
和 WidgetTester.pumpAndSettle()
来验证此行为。
pump()
只是从框架渲染一个新帧,但是 pumpAndSettle()
连续渲染帧直到没有更多的预定帧,然后 returning 预定的帧数.
一个简单(但不太精确)的测试是确保您的动画播放正确的帧数。类似于:
const expectedFramesForShake = 10;
testWidgets('example', (tester) async {
final controller = StreamController<void>();
await tester.pumpWidget(Shaker(stream: controller.stream, /* other fields */));
controller.add(null); // cause a shake
final frames = await tester.pumpAndSettle();
expect(frames, expectedFramesForShake);
});
请注意,您可能必须将小部件包装在 MaterialApp
中以设置必要的 InheritedWidget
以通过测试。
这验证了动画播放的时间大致正确,但我们可以做得更好!
与其依赖 pumpAndSettle()
到 return 计划的帧数,我们可以在每一帧之后检查小部件树。
// change this so it matches the values produced by the "correct" animation
const expectedOffsets = [0.0, 1.0, 3.0, 7.0,];
testWidgets('better example', (tester) async {
final controller = StreamController<void>();
await tester.pumpWidget(Shaker(stream: controller.stream, /* other fields */));
final offsets = <double>[]; // empty list to store results
controller.add(null);
do {
// pull the SlideTransition from the widget tree
final transition = tester.widget<SlideTransition>(find.byType<SlideTransition>);
// read the current value of the position animation
final horizontalOffset = transition.position.value.dx;
offsets.add(horizontalOffset);
// now request a new frame
await tester.pump();
// only loop while there are more frames scheduled
} while (tester.binding.hasScheduledFrame);
// compare the 2 arrays
expect(offsets, expectedOffsets);
});
这使您可以确定 Shaker
正在为每个帧偏移其子项的正确量。但是,这会使您的测试非常脆弱,例如,如果您想更改摇晃的持续时间,它将更改 offsets
.
P.S。感谢 dartpad 示例 :-)