外贸领航
首页展会信息 > flutter单元测试「(十六)Flutter入门学习之测试」

flutter单元测试「(十六)Flutter入门学习之测试」

来源:互联网 2023-05-19 15:04:00

一. 单元测试

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

1.1. 添加测试依赖

将 test 或者 flutter_test加入依赖文件,默认创建的Flutter程序已经有了依赖:

Test 包提供了编写测试所需要的核心功能

dev_dependencies:flutter_test:sdk:flutter1.2. 创建需要测试的类

单元测试通常是测试一个函数或者类,这个函数或者类被称之为是一个单元。

在这里,我们按照官方示例,创建一个简单的Counter类来演示:

classCounter{intvalue=0;voidincrement()=>value ;voiddecrement()=>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';voidmain(){test("CounterClasstest",(){//1.创建Counter并且执行操作finalcounter=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';voidmain(){group("CounterTest",(){test("CounterDefaultValue",(){expect(Counter().value,0);});test("CounterIncrementtest",(){finalcounter=Counter();counter.increment();expect(counter.value,1);});test("CounterDecrementtest",(){finalcounter=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或者,也可以使用系统快捷键!在终端执行测试

我们也可以打开终端,在工程根目录输入以下命令来执行测试:

fluttertesttest/counter_test.dart二. Widget测试

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

1.1. 添加测试依赖

Widget测试需要先给 pubspec.yaml 文件的 dev_dependencies 段添加 flutter_test 依赖。

在单元测试中我们已经说过,默认创建的Flutter项目已经添加了

dev_dependencies:flutter_test:sdk:flutter1.2. 创建测试Widget

import'package:flutter/material.dart';classHYKeywordsextendsStatelessWidget{finalList<String>keywords;HYKeywords(this.keywords);@overrideWidgetbuild(BuildContextcontext){returnScaffold(body:ListView(children:keywords.map((key){returnListTile(leading:Icon(Icons.people),title:Text(key),);}).toList(),),);}}1.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';voidmain(){testWidgets("KeywordWidgetTest",(WidgetTestertester)async{awaittester.pumpWidget(MaterialApp(title:"demo",home:HYKeywords(["abc","cba","nba"]),));finalabcText=find.text("abc");finalcbaText=find.text("cba");finalicons=find.byIcon(Icons.people);expect(abcText,findsOneWidget);expect(cbaText,findsOneWidget);expect(icons,findsNWidgets(2));});}

官方文档中还有更多关于Widget的测试:

https://flutter.dev/docs/cookbook/testing/widget/tap-drag三. 集成测试

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

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

集成测试需要有两个大的步骤

发布一个可测试应用程序到真实设备或者模拟器上;

利用独立的测试套件去驱动应用程序,检查仪器是否完好可用;

3.1. 创建可测试应用程序

我们需要创建一个可以运行在模拟器或者真实设备的应用程序。

这里我直接使用了官方的示例程序,但是不同的是我这里给两个Widget添加了两个Key

显示数字的Text Widget:ValueKey("counter")点击按钮的FloatingActionButton Widget:key: ValueKey("increment")

import'package:flutter/material.dart';voidmain()=>runApp(MyApp());classMyAppextendsStatelessWidget{//Thiswidgetistherootofyourapplication.@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:'FlutterDemo',theme:ThemeData(primarySwatch:Colors.blue,),home:MyHomePage(title:'FlutterDemoHomePage'),);}}classMyHomePageextendsStatefulWidget{MyHomePage({Keykey,this.title}):super(key:key);finalStringtitle;@override_MyHomePageStatecreateState()=>_MyHomePageState();}class_MyHomePageStateextendsState<MyHomePage>{int_counter=0;void_incrementCounter(){setState((){_counter ;});}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text(widget.title),),body:Center(child:Column(mainAxisAlignment:MainAxisAlignment.center,children:<Widget>[Text('Youhavepushedthebuttonthismanytimes:',),Text('$_counter',key:ValueKey("counter"),style:Theme.of(context).textTheme.display1,),],),),floatingActionButton:FloatingActionButton(key:ValueKey("increment"),onPressed:_incrementCounter,tooltip:'Increment',child:Icon(Icons.add),),//Thistrailingcommamakesauto-formattingnicerforbuildmethods.);}}3.2. 添加flutter_driver依赖

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

dev_dependencies:flutter_driver:sdk:flutterflutter_test:sdk:fluttertest:any3.3. 创建测试文件

和单元测试以及Widget测试不同的是,集成测试的程序和待测试的应用并不在同一个进程内,所以我们通常会创建两个文件:

文件一:用于启动带测试的应用程序文件二:编写测试的代码

我们可以将这两个文件放到一个文件中:test_driver

lib/ main.dart test_driver/ app.dart app_test.dart3.4. 编写安装应用代码

安装应用程序代码在app.dart中,分层两步完成:

让 flutter driver 的扩展可用运行应用程序

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

import'package:flutter_driver/driver_extension.dart';import'package:test_demo/main.dart'asapp;voidmain(){//开启DriverExtensionenableFlutterDriverExtension();//手动调用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';voidmain(){group("CounterAppTest",(){FlutterDriverdriver;//初始化操作setUpAll(()async{driver=awaitFlutterDriver.connect();});//测试结束操作tearDownAll((){if(driver!=null){driver.close();}});//编写测试代码finalcounterTextFinder=find.byValueKey('counter');finalbuttonFinder=find.byValueKey('increment');test("startsat0",()async{expect(awaitdriver.getText(counterTextFinder),"0");});test("ontapclick",()async{awaitdriver.tap(buttonFinder);expect(awaitdriver.getText(counterTextFinder),"1");});});}3.6. 运行集成测试

首先,启动安卓模拟器或者 iOS 模拟器,或者直接把 iOS 或 Android 真机连接到你的电脑上。

接着,在项目的根文件夹下运行下面的命令:

flutter drive --target=test_driver/app.dart

这个指令的作用:

创建 --target 目标应用并且把它安装在模拟器或真机中启动应用程序运行位于 test_driver/ 文件夹下的 app_test.dart 测试套件

运行结果:我们会发现正常运行,并且结果app中的FloatingActionButton自动被点击了一次。

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如有侵权行为,请第一时间联系我们修改或删除,多谢。

CopyRight © 外贸领航 2023 All Rights Reserved.