Day19 - Flutter - 测试用例

简介: Day19 - Flutter - 测试用例

概述


  • 单元测试
  • Widget测试
  • 集成测试


一、单元测试


单元测试是针对一个函数或者类进行测试

  • 1.1、添加测试依赖
    test 或者 flutter_test加入依赖文件,默认创建的Flutter程序已经有了依赖,Test 包提供了编写测试所需要的核心功能,在 pubspec.yaml 里面,dev_dependencies 下面的依赖在打包的时候是会被忽略掉的


dev_dependencies:
   flutter_test:
     sdk: flutter
  • 1.2、创建需要测试的类
    单元测试通常是测试一个函数或者类,这个函数或者类被称之为是一个单元。
    在这里,我们按照官方示例,创建一个简单的Counter类来演示:


class Counter {
   int value = 0;
   void increment() => value++;
   void decrement() => value--;
}
  • 1.3、创建测试文件我们在test目录下(注意:不是lib目录下),创建一个测试文件:counter_test.dart
  • 通常测试代码都会放在该目录下,并且测试文件不会打包到最终的应用程序中;
  • 测试文件通常以 _test.dart 命名,这是 test runner 寻找测试文件的惯例


import 'package:flutter_test/flutter_test.dart';
import 'package:test_demo/counter.dart';
void main() {
    test("Counter Class test", () {
        // 1.创建Counter并且执行操作
       final counter = Counter();
       counter.increment();
       // 2.通过expect来监测结果正确与否
       expect(counter.value, 1);
    });
}
  • 1.4、整合多个测试
    如果对同一个类或函数有多个测试,我们希望它们关联在一起进行测试,可以使用 group


import 'dart:math';
import 'package:flutter_test/flutter_test.dart';
import 'package:test_demo/counter.dart';
void main() {
   group("Counter Test", () {
       test("Counter Default Value", () {
          expect(Counter().value, 0);
       });
       test("Counter Increment test", () {
          final counter = Counter();
          counter.increment();
          expect(counter.value, 1);
       });
       test("Counter Decrement test", () {
          final counter = Counter();
          counter.decrement();
          expect(counter.value, -1);
       });
  });
}


  • 1.5. 执行测试结果用 IntelliJ 或 VSCode 执行测试IntelliJ 和 VSCode 的 Flutter 插件支持执行测试。用这种方式执行测试是最好的,因为它可以提供最快的反馈闭环,而且还支持断点调试。
  • IntelliJ
  • 打开文件 counter_test.dart
  • 选择菜单 Run
  • 点击选项 Run 'tests in counter_test.dart'
  • 或者,也可以使用系统快捷键!
  • VSCode
  • 打开文件 counter_test.dart
  • 选择菜单 Debug
  • 点击选项 Start Debugging
  • 或者,也可以使用系统快捷键!
  • 在终端执行测试
    我们也可以打开终端,在工程根目录输入以下命令来执行测试:


flutter test test/counter_test.dart


二、Widget测试


Widget测试主要是针对某一个封装的Widget进行单独测试

  • 2.1、添加测试依赖
    Widget 测试需要先给 pubspec.yaml 文件的 dev_dependencies 段添加 flutter_test 依赖。在单元测试中我们已经说过,默认创建的Flutter项目已经添加了


dev_dependencies:
    flutter_test:
       sdk: flutter
  • 2.2. 创建测试Widget


import 'package:flutter/material.dart';
class HYKeywords extends StatelessWidget {
     final List<String> keywords;
     HYKeywords(this.keywords);
     @override
     Widget build(BuildContext context) {
        return Scaffold(
            body: ListView(
             children: keywords.map((key) {
                return ListTile(
                    leading: Icon(Icons.people),
                    title: Text(key),
                );
             }).toList(),
           ),
        );
      }
}


  • 2.3、编写测试代码创建对应的测试文件,编写对应的测试代码:
  • testWidgets:flutter_test中用于测试Widget的函数;
  • tester.pumpWidget:pumpWidget 方法会建立并渲染我们提供的 widget;
  • find:find() 方法来创建我们的 Finders;
  • findsNothing:验证没有可被查找的 widgets。
  • findsWidgets:验证一个或多个 widgets 被找到。
  • findsNWidgets:验证特定数量的 widgets 被找到。


import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:test_demo/keywords.dart';
void main() {
    testWidgets("KeywordWidget Test", (WidgetTester tester) async {
         await tester.pumpWidget(MaterialApp(title: "demo", home: JKKeywords(["abc", "cba", "nba"]),) );
         final abcText = find.text("abc");
         final cbaText = find.text("cba");
         final icons = find.byIcon(Icons.people);
        expect(abcText, findsOneWidget);
        expect(cbaText, findsOneWidget);
        expect(icons, findsNWidgets(2));
    });
}



三、集成测试



单元测试和Widget测试都是在测试独立的类或函数或Widget,它们并不能测试单独的模块形成的整体或者获取真实设备或模拟器上应用运行的状态;

这些测试任务可以交给 集成测试 来完成;


集成测试 需要有两个大的步骤:1、发布一个可测试应用程序到真实设备或者模拟器上;2、利用独立的测试套件去驱动应用程序,检查仪器是否完好可用;

  • 3.1、创建可测试应用程序我们需要创建一个可以运行在模拟器或者真实设备的应用程序。这里我直接使用了官方的示例程序,但是不同的是我这里给两个Widget添加了两个Key
  • 显示数字的 Text Widget:ValueKey("counter")
  • 点击按钮的 FloatingActionButton Widget:key: ValueKey("increment")


import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
    // This widget is the root of your application.
    @override
    Widget build(BuildContext context) {
       return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
             primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
       );
    }
}
class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
      final String title;
      @override
      _MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
      int _counter = 0;
      void _incrementCounter() {
          setState(() {
             _counter++;
          });
      }
      @override
      Widget build(BuildContext context) {
         return Scaffold(
            appBar: AppBar(
                title: Text(widget.title),
            ),
            body: Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                     Text(
                        'You have pushed the button this many times:',
                     ),
                     Text(
                        '$_counter',
                        key: ValueKey("counter"),
                        style: Theme.of(context).textTheme.display1,
                     ),
                  ],
                ),
            ),
            floatingActionButton: FloatingActionButton(
                key: ValueKey("increment"),
                onPressed: _incrementCounter,
                tooltip: 'Increment',
                child: Icon(Icons.add),
            ), // This trailing comma makes auto-formatting nicer for build methods.
         );
      }
}


  • 3.2. 添加flutter_driver依赖
    我们需要用到 flutter_driver 包来编写 集成测试,所以我们需要把 flutter_driver 依赖添加到应用pubspec.yaml 文件的 dev_dependencies 位置:


dev_dependencies:
    flutter_driver:
       sdk: flutter
    flutter_test:
       sdk: flutter
    test: any
  • 3.3. 创建测试文件和单元测试以及Widget测试不同的是,集成测试的程序和待测试的应用并不在同一个进程内,所以我们通常会创建两个文件:
  • 文件一:用于启动带测试的应用程序
  • 文件二:编写测试的代码
  • 我们可以将这两个文件放到一个文件中:test_driver,目录结构如下


image.png


image.png

  • .4. 编写安装应用代码安装应用程序代码在 app.dart 中,分层两步完成:
  • flutter driver  的扩展可用
  • 运行应用程序


  • test_driver/app.dart 文件中增加以下代码:


import 'package:flutter_driver/driver_extension.dart';
import 'package:test_demo/main.dart' as app;
void main() {
   // 开启DriverExtension
   enableFlutterDriverExtension();
   // 手动调用main函数, 启动应用程序
   app.main();
}
  • 3.5. 编写集成测试代码现在我们有了待测应用,我们可以为它编写测试文件了。这包含了四个步骤:
  • 创建 SerializableFinders 定位指定组件
  • 在 setUpAll() 函数中运行测试案例前,先与待测应用建立连接
  • 测试重要场景
  • 完成测试后,在 teardownAll() 函数中与待测应用断开连接
  • test_driver/app_test.dart 文件中增加以下代码:


import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart';
void main() {
    group("Counter App Test", () {
       FlutterDriver driver;
       // 初始化操作
      setUpAll(() async {
         driver = await FlutterDriver.connect();
      });
      // 测试结束操作
      tearDownAll(() {
         if (driver != null) {
            driver.close();
         }
      });
      // 编写测试代码
      final counterTextFinder = find.byValueKey('counter');
      final buttonFinder = find.byValueKey('increment');
      test("starts at 0", () async {
         expect(await driver.getText(counterTextFinder), "0");
      });
      test("on tap click", () async {
           await driver.tap(buttonFinder);
           expect(await driver.getText(counterTextFinder), "1");
      });
   });
}
  • 3.6. 运行集成测试首先,启动安卓模拟器或者 iOS 模拟器,或者直接把 iOS 或 Android 真机连接到你的电脑上。接着,在项目的根文件夹下运行下面的命令


flutter drive --target=test_driver/app.dart


  • 这个指令的作用:
  • 创建 --target 目标应用并且把它安装在模拟器或真机中
  • 启动应用程序
  • 运行位于 test_driver/ 文件夹下的 app_test.dart 测试套件
  • 运行结果:我们会发现正常运行,并且结果app中的FloatingActionButton自动被点击了一次


目录
相关文章
|
11天前
|
缓存 监控 前端开发
【Flutter前端技术开发专栏】Flutter应用的性能调优与测试
【4月更文挑战第30天】本文探讨了Flutter应用的性能调优策略和测试方法。性能调优对提升用户体验、降低能耗和增强稳定性至关重要。优化布局(避免复杂嵌套,使用`const`构造函数)、管理内存、优化动画、实现懒加载和按需加载,以及利用Flutter的性能工具(如DevTools)都是有效的调优手段。性能测试包括基准测试、性能分析、压力测试和电池效率测试。文中还以ListView为例,展示了如何实践这些优化技巧。持续的性能调优是提升Flutter应用质量的关键。
【Flutter前端技术开发专栏】Flutter应用的性能调优与测试
|
11天前
|
前端开发 测试技术 持续交付
【Flutter 前端技术开发专栏】Flutter 中的 UI 测试与自动化测试
【4月更文挑战第30天】本文探讨了 Flutter 应用中UI测试和自动化测试的重要性,包括保障质量、提高效率和增强开发信心。Flutter提供`flutter_test`库进行Widget测试,以及`flutter_driver`进行集成测试。UI测试涵盖界面布局、交互和状态变化的验证,最佳实践建议尽早引入测试、保持用例简洁,并结合手动测试。未来,随着Flutter技术发展,UI测试和自动化测试将更加完善,助力开发高质量应用。
【Flutter 前端技术开发专栏】Flutter 中的 UI 测试与自动化测试
|
Dart 测试技术 API
【Flutter】大型项目里Flutter测试应用实例以及集成测试的深度使用
【Flutter】大型项目里Flutter测试应用实例以及集成测试的深度使用
|
测试技术 Android开发 iOS开发
Flutter测试
单元测试是针对一个函数或者类进行测试
164 0
|
Dart
【Flutter】HTTP 网络操作 ( 引入 http 插件 | 测试网站 | Get 请求 | Post 请求 | 将响应结果转为 Dart 对象 | Future 异步调用 )(二)
【Flutter】HTTP 网络操作 ( 引入 http 插件 | 测试网站 | Get 请求 | Post 请求 | 将响应结果转为 Dart 对象 | Future 异步调用 )(二)
244 0
【Flutter】HTTP 网络操作 ( 引入 http 插件 | 测试网站 | Get 请求 | Post 请求 | 将响应结果转为 Dart 对象 | Future 异步调用 )(二)
|
存储 JSON Dart
【Flutter】HTTP 网络操作 ( 引入 http 插件 | 测试网站 | Get 请求 | Post 请求 | 将响应结果转为 Dart 对象 | Future 异步调用 )(一)
【Flutter】HTTP 网络操作 ( 引入 http 插件 | 测试网站 | Get 请求 | Post 请求 | 将响应结果转为 Dart 对象 | Future 异步调用 )(一)
393 0
【Flutter】HTTP 网络操作 ( 引入 http 插件 | 测试网站 | Get 请求 | Post 请求 | 将响应结果转为 Dart 对象 | Future 异步调用 )(一)
|
Dart
Flutter之基本数据类型测试
Flutter之基本数据类型测试
128 0
Flutter之测试Http和HttpClient
Flutter之测试Http和HttpClient
192 0
Flutter之测试Http和HttpClient
|
JSON 编解码 文字识别
Flutter UI自动化测试技术方案选型与探索
Flutter页面无法直接使用Native测试工具定位元素,给自动化测试带来很多不便。虽然Google官方推出了Flutter driver 和 Integration test,但是在实际使用中存在以下问题:
509 0
Flutter UI自动化测试技术方案选型与探索
|
JSON 编解码 文字识别