当一个团队配合完成app开发的时候,尤其在需求大方向确定,磨合期过了之后速度是很快的。这个时候如何保证大家在添加代码的时候整个app都是可以正确运行的,那就只有编写测试了。
自动化测试可以氛围一下的类型:- 单元测试,测试一个单个的方法,函数或者类。
- Widget测试,测试一个(其他UI框架有时也叫组件)widget。
- 集成测试,测试整个的app或者这个app的一大部分。
这三类测试的消费比:
单元测试单元测试通常用来验证一个方法、函数或者一个类可用。test包提供了编写单元测试需要的主要功能,flutter_test包提供了额外的一些工具方法。
编写单元测试需要一下步骤:1. 添加test或者flutter_test包依赖
- 新建一个测试文件
- 开始编写测试
- 把多个测试整合到一个group里
- 运行测试### 1、添加test依赖### 2、新建一个测试文件在新建我们的flutter_todo项目的时候,已经生成了一个测试文件。在test/unit_test.dart。这里测试了1+1=2这个最简单的加法。
我们用这个测试来测试项目中的todo列表、添加、更新和删除功能。这些代码都是异步执行的,所以和上面看起来的最简单测试略有不同。为了测试http请求,这里我们需要对http客户端做模拟,所以需要mockito。
3、编写测试首先安装mockito以及build_runner
的依赖:mockito用来模拟需要的一些依赖,而build_runner让某些运行测试需要的代码根据配置生成出来。
现在看看我们要测试的代码:
这个类用来实现http请求。它有一个属性client,请求网络的主要功能就在这个实行上执行。它也是我们需要模拟的。
在新建项目的时候自动生成的测试文件unit_test.dart里修改代码:
首先在main方法上添加一个注解@GenerateMocks([http.Client])。然后就需要build_runner出场了。执行dart run build_runner build。在注解里配置的需要模拟的依赖就会被自动生成出来,生成到了unit_test.mocks.dart文件。这个文件就在unit_test.dart同一个目录下。
之后,把生成出来的MockClient初始化并赋值给HttpRequest实例的client属性。
在when语句里加上模拟的数据:
最后用expect语句检查你的代码是否正常:### 4、给测试分组在test语句的外面加上group语句就可以:
5、运行测试执行命令或者在你喜欢的工具里运行测试。比如在VS Code里:点击就可以运行你的测试代码。## Widget测试前面已经讲了单元测试。需要测试widget则需要flutter_teset包。首先就需要添加这个依赖:这里依赖其实在自动新建项目的时候添加好了。
添加依赖之后就可以开始编写测试了:在调用pumpWidget方法之后tester就会把组件绘制出来。但是,对于一个StatefulWidget来说,如果你调用了setState方法之后,测试环境是不会自动绘制这个widget的。只有调用pump方法才行。同时对于动画的测试也需要这样处理。要开始动画,需要调用pump()一次,否则动画不会开始。
使用Finder查找我们需要验证的widget。如果是根据文本内容查找则可以使用find.text('some text')方法实现。比如:根据文本找widget,如果这个widget找到了那么就是测试成功了。下面添加验证代码:
前面的测试代码有一个很大的问题。笔者在一开始写的时候也忽略了这个显而易见的问题。在测试你的widget的时候必须把它放在MaterialApp / Scaffold的body属性里才可以执行内存绘制,否则会直接报错。
修改之后是这样的:在内存绘制之后,使用Finder找到目标widget,并验证是否找到了这么一个Text。
运行之后,测试通过!## 集成测试单元测试和widget测试可以方便的测试单个的方法或者widget。但是要测试一整块的功能就需要继承测试。集成测试使用SDK自带的integration_test包来实现的。这里我们用继承测试来测试todo app。
1、添加integration_test依赖
2、编写测试首先需要在项目下建立一个目录integration_test,然后在这个目录下新建一个文件app_test.dart。
在app_test.dart文件里,需要在main方法下初始化IntegrationTestWidgetsFlutterBinding,这样测试才可以运行在设备。
现在正式开始编写测试。我们首先需要确保在列表页可以正确的显示出todo。这次是测试app,所以一开始先渲染整个的app:
这和widget测试的实现方式类似,只是这一次不需要在widget包装一层material app和scaffold了。app本身就包含了这些。
Todo app在实现的时候也使用了get_x库,所以整个app的渲染用的是最外层的·widget。
注意第15行:await tester.pumpAndSettle()。todo app是需要访问后台获取数据的,在获得所需要的数据之后会更新状态,把数据绘制在app的列表页。这行代码之所以重要,是因为如果没有这行的代码,后面的expect只会有一个结果:失败。
在所有的实现了setState的widget中,都需要调用dump()或者dumpAndSettle()来达到让widget重绘的目的。比如,widget包含了动画,widget有网络请求并要根据返回的数据做出不同的显示的时候。
15行之后的代码就和widget测试是一样的。
3、运行测试运行这个继承测试。这个测试很简单,可以直接成功了。但是,需要注意你的后端返回的数据是否包含hello文本,如果没有,那需要换到你返回了的数据。如果你测试的场景是无数据的,那么在expect里要检查的就是没有文本显示这个场景。
Flutter web的测试Flutter web的测试需要额外的配置。1、下载ChromeDriver,在这里下载。注意:下载的是chromedriver,不是chrome for test。2、解压,把chromedriver放在一个目录下3、添加环境变量
这些都做好之后运行:让chromedriver在4444端口下运行起来。
另外一个重要的配置就是在项目下新建一个目录test_driver,在里面新建一个文件integration_test.dart。在文件里加上代码:
之后就可以开始测试了
或者如果要在无头模式下测试:
运行的结果是这样的: