Val*_*nal 5 testing mocking dart flutter flutter-test
我正在尝试为我的 Flutter 应用程序创建测试。简单的例子:
class MyWidget extends StatelessWidget {
   @override
   build(BuildContext context) {
      return MySecondWidget();
   }
}
我想验证它MyWidget实际上是在MySecondWidget没有构建的情况下调用MySecondWidget。
void main() {
   testWidgets('It should call MySecondWidget', (WidgetTester tester) async {
      await tester.pumpWidget(MyWidget());
      expect(find.byType(MySecondWidget), findsOneWidget);
   }
}
在我的情况下,这将不起作用,因为MySecondWidget需要一些特定且复杂的设置(例如 API 密钥、...中的值Provider)。我想要的是“模拟” MySecondWidget为空Container(例如),以便在测试期间不会引发任何错误。
我怎么能做这样的事情?
没有任何开箱即用的方法可以模拟小部件。我将写一些关于如何在测试期间“模拟”/替换小部件的示例/想法(例如使用SizedBox.shrink().
但首先,让我解释一下为什么我认为这不是一个好主意。
在 Flutter 中,您正在构建一个 widget 树。一个特定的小部件有一个父部件,并且通常有一个或多个子部件。
出于性能原因,Flutter 选择了单通道布局算法(请参阅此):
Flutter 每帧执行一次布局,并且布局算法在单遍中工作。父对象调用其每个子对象的布局方法,将约束沿着树向下传递。子级递归地执行自己的布局,然后通过从其布局方法返回将几何图形返回到树上。重要的是,一旦渲染对象从其布局方法返回,在下一帧的布局之前将不会再次访问该渲染对象。这种方法将原本可能是单独的测量和布局传递合并到单个传递中,因此,每个渲染对象在布局期间最多被访问两次:一次在树下的路径上,一次在树上的路径上。
由此,我们需要了解父级需要其子级进行构建以获得其大小,然后正确渲染自身。如果删除它的子项,它的行为可能会完全不同。
如果可能的话,最好模拟服务。例如,如果您的孩子发出 HTTP 请求,您可以模拟 HTTP 客户端:
HttpOverrides.runZoned(() {
  // Operations will use MyHttpClient instead of the real HttpClient
  // implementation whenever HttpClient is used.
}, createHttpClient: (SecurityContext? c) => MyHttpClient(c));
如果孩子需要特定的提供者,您可以提供一个虚拟的提供者:
testWidgets('My test', (tester) async {
  tester.pumpWidget(
    Provider<MyProvider>(
      create: (_) => MyDummyProvider(),
      child: MyWidget(),
    ),
  );
});
如果您仍然想在测试期间用另一个小部件更改一个小部件,这里有一些想法:
Platform.environment.containsKey('FLUTTER_TEST')您可以Platform从dart:io(网络上不支持)或universal_io(网络上支持)导入。
你的构建方法可以是:
@override
Widget build(BuildContext context) {
  final isTest = Platform.environment.containsKey('FLUTTER_TEST');
  if (isTest) return const SizedBox.shrink();
  return // Your real implementation.
}
@visibleForTestingmockChild您可以注释仅在测试文件中可见/可用的参数(例如:):
class MyWidget extends StatelessWidget {
  const MyWidget({
    @visibleForTesting this.mockChild,
  });
  
  final Widget? child;
  @override
  Widget build(BuildContext context) {
    return mockChild ??  // Your real widget implementation here.
  }
}
在你的测试中:
tester.pumpWidget(
  MyWidget(
    mockChild: MyMockChild(),
  ),
);
| 归档时间: | 
 | 
| 查看次数: | 354 次 | 
| 最近记录: |