You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中如何测试延迟3秒渲染的Container组件?

场景

页面包含两个按钮:

  • 点击第一个按钮,立即渲染蓝色Container
  • 点击第二个按钮,延迟3秒后渲染红色Container

代码

loginpage_test.dart

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  testWidgets('test for blue and red boxes', (tester) async {
    // Arrange
    await tester.pumpWidget(const MainApp());
    await tester.pumpWidget(const MaterialApp(
      home: DashboardPage(),
    ));

    // Act
    Finder blueButtonFinder = find.byKey(const ValueKey('BlueButton'));
    Finder blueBoxFinder = find.byKey(const ValueKey('BlueBox'));
    Finder redButtonFinder = find.byKey(const ValueKey('RedButton'));
    Finder redBoxFinder = find.byKey(const ValueKey('RedBox'));

    // Assert
    expect(blueButtonFinder, findsOneWidget);
    expect(blueBoxFinder, findsNothing);
    expect(redButtonFinder, findsOneWidget);
    expect(redBoxFinder, findsNothing);

    await tester.tap(blueButtonFinder);
    await tester.pumpAndSettle();
    expect(blueBoxFinder, findsOneWidget);

    await tester.runAsync(() async {
      await tester.tap(redButtonFinder);
      // await tester.binding.delayed(const Duration(seconds: 3));
      await tester.pumpAndSettle();
      // await tester.pump(Duration(seconds: 3));
    });

    expect(redBoxFinder, findsOneWidget);
  });
}

dashboardpage.dart

class DashboardPage extends StatefulWidget {
  const DashboardPage({super.key});

  @override
  State<DashboardPage> createState() => _DashboardPageState();
}

class _DashboardPageState extends State<DashboardPage> {
  bool isShowBlue = false;
  bool isShowRed = false;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: AppColors.black20,
      appBar: AppBar(
        leading: Icon(Icons.menu_rounded, size: 24.w),
        actions: AppbarActions.appBarActions,
        backgroundColor: Colors.transparent,
        elevation: 0,
        systemOverlayStyle: CustomOverlays.appbarOverlayLight,
      ),
      body: Padding(
        padding: EdgeInsets.symmetric(horizontal: 16.w),
        child: Column(
          children: [
            CoverPictureSection(),
            SizedBox(height: 10.h),
            ElevatedButton(
              key: const ValueKey('BlueButton'),
              onPressed: () {
                setState(() {
                  isShowBlue = true;
                });
              },
              child: const Text('Create Blue Box'),
            ),
            SizedBox(height: 10.h),
            isShowBlue
                ? Container(
                    key: const ValueKey('BlueBox'),
                    width: 50.w,
                    height: 50.h,
                    color: Colors.blue,
                  )
                : const SizedBox.shrink(),
            SizedBox(height: 10.h),
            ElevatedButton(
              key: const ValueKey('RedButton'),
              onPressed: () async {
                await Future.delayed(const Duration(seconds: 3));
                setState(() {
                  isShowRed = true;
                });
              },
              child: const Text('Create Red Box'),
            ),
            SizedBox(height: 10.h),
            isShowRed
                ? Container(
                    key: const ValueKey('RedBox'),
                    width: 50.w,
                    height: 50.h,
                    color: Colors.red,
                  )
                : const SizedBox.shrink(),
          ],
        ),
      ),
    );
  }
}

问题

蓝色盒子的测试可以成功,但红色盒子的测试失败,报错信息如下:

══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure was thrown running a test:
Expected: exactly one matching candidate
Actual: _KeyWidgetFinder:<Found 0 widgets with key [<'RedBox'>]: []>
Which: means none were found but one was expected

断言红色盒子存在时,对应的延迟Future还未完成。尝试将tester.tap放入runAsync()中,仍无法解决问题。

解决方案

测试延迟渲染组件的核心是让测试框架等待延迟完成并触发UI更新,具体修改如下:

1. 调整测试代码中的延迟处理

移除runAsync(),直接在点击红色按钮后调用tester.pump()传入延迟时长,再用tester.pumpAndSettle()确保UI更新完成:

// 替换原有的runAsync代码块
await tester.tap(redButtonFinder);
// 推进测试时间到延迟结束(无需真实等待3秒,测试框架会加速时间)
await tester.pump(const Duration(seconds: 3));
// 等待所有UI更新和动画完成
await tester.pumpAndSettle();
expect(redBoxFinder, findsOneWidget);

2. 完整修改后的测试代码

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  testWidgets('test for blue and red boxes', (tester) async {
    // Arrange
    await tester.pumpWidget(const MainApp());
    await tester.pumpWidget(const MaterialApp(
      home: DashboardPage(),
    ));

    // Act
    Finder blueButtonFinder = find.byKey(const ValueKey('BlueButton'));
    Finder blueBoxFinder = find.byKey(const ValueKey('BlueBox'));
    Finder redButtonFinder = find.byKey(const ValueKey('RedButton'));
    Finder redBoxFinder = find.byKey(const ValueKey('RedBox'));

    // Assert
    expect(blueButtonFinder, findsOneWidget);
    expect(blueBoxFinder, findsNothing);
    expect(redButtonFinder, findsOneWidget);
    expect(redBoxFinder, findsNothing);

    await tester.tap(blueButtonFinder);
    await tester.pumpAndSettle();
    expect(blueBoxFinder, findsOneWidget);

    // 修改后的红色按钮测试逻辑
    await tester.tap(redButtonFinder);
    await tester.pump(const Duration(seconds: 3));
    await tester.pumpAndSettle();
    expect(redBoxFinder, findsOneWidget);
  });
}

内容的提问来源于stack exchange,提问作者Ayan Dasgupta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 07:01:03