Flutter测试框架插件given_when_then的使用

发布于 1周前 作者 zlyuanteng 来自 Flutter

Flutter测试框架插件given_when_then的使用

given_when_then是一个Flutter包,旨在使测试更加易读。如果你还不熟悉Flutter的Widget测试,请先花点时间了解一下。

原则

  • Given:我们觉得测试是代码行为的最佳文档。
  • When:当我们阅读我们的测试时。
  • Then:我们希望它们易于理解。

虽然Flutter的Widget测试非常强大,但有时会显得有些冗长。这个包的目的是通过复用代码来简化测试,并使其更易读。

示例对比

传统方式(不使用given_when_then

testWidgets('MyWidget has a title and message', (WidgetTester tester) async {
    await tester.pumpWidget(MyWidget(title: 'T', message: 'M'));
    final titleFinder = find.text('T');
    final messageFinder = find.text('M');

    // 使用 `findsOneWidget` 匹配器验证 Text 小部件在小部件树中出现一次。
    expect(titleFinder, findsOneWidget);
    expect(messageFinder, findsOneWidget);
});

使用given_when_then的方式

testWidgets('MyWidget has a title and message', harness((given, when, then) async {
    await given.pumpMyWidget(title: 'T', message: 'M');
    then.myTitleIs('T');
    then.myMessageIs('M');
}));

可以看到,通过将细节移动到WidgetTestGivenWidgetTestWhenWidgetTestThen类中,我们可以去除不必要的细节,使测试更加简洁明了。

完整示例Demo

为了更好地展示如何使用given_when_then,下面是一个完整的示例:

首先,在你的pubspec.yaml文件中添加依赖:

dependencies:
  flutter:
    sdk: flutter
  given_when_then: ^0.1.0 # 确保使用最新版本

dev_dependencies:
  flutter_test:
    sdk: flutter

接下来,创建一个简单的Widget进行测试:

import 'package:flutter/material.dart';

class MyWidget extends StatelessWidget {
  final String title;
  final String message;

  MyWidget({required this.title, required this.message});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text(title)),
        body: Center(child: Text(message)),
      ),
    );
  }
}

然后,编写测试代码:

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:given_when_then/given_when_then.dart';
import 'my_widget.dart'; // 引入上面定义的MyWidget

void main() {
  testWidgets('MyWidget has a title and message', harness((given, when, then) async {
    await given.pumpMyWidget(title: 'Hello', message: 'World');
    then.myTitleIs('Hello');
    then.myMessageIs('World');
  }));
}

// 自定义的辅助函数
extension Given on WidgetTestGiven {
  Future<void> pumpMyWidget({required String title, required String message}) async {
    await pumpWidget(MaterialApp(
      home: MyWidget(title: title, message: message),
    ));
  }
}

extension Then on WidgetTestThen {
  void myTitleIs(String expectedTitle) {
    expect(find.text(expectedTitle), findsOneWidget);
  }

  void myMessageIs(String expectedMessage) {
    expect(find.text(expectedMessage), findsOneWidget);
  }
}

以上就是如何使用given_when_then插件来编写更清晰、更易维护的测试代码的方法。更多详细信息可以参考官方示例


更多关于Flutter测试框架插件given_when_then的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter测试框架插件given_when_then的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,given_when_then 是一个在 Flutter 测试中用于结构化测试逻辑的流行模式。虽然它不是一个官方的 Flutter 插件,但它可以通过一些辅助函数或自定义的封装来实现。下面是一个如何在 Flutter 测试中使用 given_when_then 模式的示例。

首先,我们假设我们有一个简单的 Flutter 应用,它有一个计数器,用户可以通过按钮来增加计数。

1. 示例应用代码

// main.dart
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterScreen(),
    );
  }
}

class CounterScreen extends StatefulWidget {
  @override
  _CounterScreenState createState() => _CounterScreenState();
}

class _CounterScreenState extends State<CounterScreen> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter App'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

2. 测试代码

接下来,我们使用 given_when_then 模式来编写测试代码。我们将使用 Flutter 的测试框架 flutter_test

// counter_screen_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'main.dart';

void main() {
  testWidgets('Counter increments smoke test', (WidgetTester tester) async {
    // Given: A counter with initial value 0
    await tester.pumpWidget(MaterialApp(home: CounterScreen()));

    // Find the text widget that displays the counter value.
    final counterTextFinder = find.text('0');
    expect(counterTextFinder, findsOneWidget);

    // When: The button is tapped
    await tester.tap(find.byIcon(Icons.add));
    await tester.pump(); // This pumps a frame to update the UI

    // Then: The counter value is incremented by 1
    final counterTextAfterIncrement = find.text('1');
    expect(counterTextAfterIncrement, findsOneWidget);
  });
}

解释

  1. Given: 设置测试的前提条件。在这里,我们通过 tester.pumpWidget 方法渲染了 CounterScreen 组件,并检查初始计数是否为 0
  2. When: 模拟用户操作。在这个例子中,我们通过 tester.tap 方法模拟了用户点击浮动按钮的操作,并通过 tester.pump 方法更新了 UI。
  3. Then: 验证结果。我们检查更新后的计数是否为 1

通过这种方式,我们可以确保我们的测试代码清晰、结构化,并且易于理解和维护。这种 given_when_then 模式不仅适用于 Flutter 测试,也广泛适用于其他类型的软件测试。

回到顶部