Flutter 测试

本节将介绍 Flutter 中的三种测试类型:单元测试、Widget 测试和集成测试。


测试类型概述

类型说明运行命令
单元测试测试单个函数、类的方法flutter test
Widget 测试测试单个 Widget 的 UIflutter test
集成测试测试完整的应用流程flutter test integration_test/

单元测试

单元测试用于测试业务逻辑代码。

实例:单元测试示例

// math_utils.dart - 待测试的代码
class MathUtils {
  static int add(int a, int b) => a + b;
  static int subtract(int a, int b) => a - b;
  static int multiply(int a, int b) => a * b;
  static double divide(int a, int b) {
    if (b == 0) throw ArgumentError('不能除以零');
    return a / b;
  }

  static int factorial(int n) {
    if (n < 0) throw ArgumentError('负数没有阶乘');
    if (n == 0 || n == 1) return 1;
    return n * factorial(n - 1);
  }
}

// math_utils_test.dart - 测试文件
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/math_utils.dart';

void main() {
  group('MathUtils', () {
    test('add 两个数相加', () {
      expect(MathUtils.add(2, 3), equals(5));
    });

    test('subtract 两个数相减', () {
      expect(MathUtils.subtract(5, 3), equals(2));
    });

    test('multiply 两个数相乘', () {
      expect(MathUtils.multiply(4, 5), equals(20));
    });

    test('divide 两个数相除', () {
      expect(MathUtils.divide(10, 2), equals(5));
    });

    test('divide 除以零抛出异常', () {
      expect(() => MathUtils.divide(10, 0), throwsArgumentError);
    });

    test('factorial 计算阶乘', () {
      expect(MathUtils.factorial(5), equals(120));
      expect(MathUtils.factorial(0), equals(1));
    });

    test('factorial 负数抛出异常', () {
      expect(() => MathUtils.factorial(-1), throwsArgumentError);
    });
  });
}

Widget 测试

Widget 测试用于测试 UI 组件。

实例:Widget 测试

// counter_widget.dart - 待测试的 Widget
class CounterWidget extends StatefulWidget {
  const CounterWidget({super.key});

  @override
  State<CounterWidget> createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  int _count = 0;

  void _increment() {
    setState(() {
      _count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Text('计数: $_count', key: const Key('counter_text')),
        ElevatedButton(
          key: const Key('increment_button'),
          onPressed: _increment,
          child: const Text('增加'),
        ),
      ],
    );
  }
}

// counter_widget_test.dart - 测试文件
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/counter_widget.dart';

void main() {
  testWidgets('CounterWidget 显示初始计数', (WidgetTester tester) async {
    // 构建 Widget
    await tester.pumpWidget(const MaterialApp(
      home: CounterWidget(),
    ));

    // 验证初始计数显示
    expect(find.text('计数: 0'), findsOneWidget);
  });

  testWidgets('CounterWidget 点击按钮增加计数', (WidgetTester tester) async {
    await tester.pumpWidget(const MaterialApp(
      home: CounterWidget(),
    ));

    // 找到并点击按钮
    await tester.tap(find.byKey(const Key('increment_button')));
    await tester.pump();

    // 验证计数已更新
    expect(find.text('计数: 1'), findsOneWidget);

    // 再次点击
    await tester.tap(find.byKey(const Key('increment_button')));
    await tester.pump();

    expect(find.text('计数: 2'), findsOneWidget);
  });
}

集成测试

集成测试用于测试完整的应用功能流程。

实例:集成测试

// integration_test/app_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.dart';

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  group('应用集成测试', () {
    testWidgets('完整用户流程测试', (WidgetTester tester) async {
      // 启动应用
      await tester.pumpWidget(const MyApp());
      await tester.pumpAndSettle();

      // 验证首页显示
      expect(find.text('首页'), findsOneWidget);

      // 点击跳转到详情页
      await tester.tap(find.text('详情'));
      await tester.pumpAndSettle();

      // 验证详情页显示
      expect(find.text('详情页'), findsOneWidget);

      // 点击返回
      await tester.tap(find.byIcon(Icons.arrow_back));
      await tester.pumpAndSettle();

      // 验证回到首页
      expect(find.text('首页'), findsOneWidget);
    });
  });
}

良好的测试覆盖可以提高代码质量,建议至少对核心业务逻辑编写单元测试。