在Flutter Test官方的CI方案中,包含UnitTest/WidgetTest/DriverTest三种模式,其中UnitTest/WidgetTest是可以在代码的沙盒环境下运行,而Driver Test需要依赖整包构建;大家都知道在单元测试过程中发现问题成本最低,而整包构建耗时比较久,因此这里介绍一种通用的Flutter Test在CI阶段的方案;
Flutter CI自动化检测能力主要通过FlutterTest能力建设,但具体数据能力建设稍有不足,主要原因是
- FlutterTest不支持直接发送一个http请求功能;
- 以及大量的Channel数据需要主动MOCK,如果大型应用需要mock的太多太杂;
同理可以看在stackoverflow上也有很多人咨询过为什么flutter test环境下无法运行一个HTTP服务请求; https://stackoverflow.com/questions/62184160/flutter-testing-passing-an-actual-http-client-instead-of-a-mocked-one
其实分析主要原因是一个在Flutter Test的沙盒环境下,无法运行engine侧很多代码,导致socket服务不能正常发,因此在CI下网络服务是断开的;鉴于此很多mock服务比如flutter mockite就提供一种方案自己维护mock数据,但是这种方式维护成本就非常高了,大家都是程序员,谁也不愿意去维护mock数据,何况业务天天变动情况下; 分析下其思路主要是通过setupMockHttpOverrides覆盖全局的Http,然后将请求服务转接到mock处理逻辑中;
void setupMockHttpOverrides() {
HttpOverrides.global = MockHttpOverrides();
}
/// mock 模拟 http
class MockClient extends Mock implements http.Client {}
void main() {
test("testHttp", () async {
final client = MockClient();
when(client.get("xxxx"))
.thenAnswer((_) async {
return http.Response(
'{"title": "test title", "body": "test body"}', 200);
});
var post = await fetchPost(client);
expect(post.title, "test title");
});
2. 方案
介绍了上述的那种方案,肯定狗都直摇头,本文主要介绍一种投机方案解决CI服务,我们发现,flutterTest是可以运行一些Dart代码,但是httpClient运行到sky_engine的一些代码逻辑时候就没有返回值,导致无法发送一个http请求出去,但是无意偶然机会发现官方介绍Process,其通过Process.run可以实现一些shell命令:
既然可以运行Shell命令,即可以通过CURL发送一个http请求,在flutterTest环境中发送如下:
test('httpTest', () async {
ProcessResult result = await Process.run('curl', [
'http://www.baidu.com',
]);
String serverResponse = result.stdout();
});
遗憾是实际测试发现在flutterTest环境中运行在Process.run也卡住没有返回值,跟进代码发现有一个同步方式Process.runSyn发现可以正常返回值:
image.png于是乎我们就可以使用Process.runSyn方法通过CURL命令绕过HTTP服务缺陷,发送一个真实的网络服务了;
解决完网络服务,其次就是Channel服务能力,这块官方的推荐方案是:
MethodChannel('flutter_mock_service').setMockMethodCallHandler((MethodCall methodCall) async {
if (methodCall.method == 'getPlatformVersionMock') {
return 'Android 11 Mock';
}
return null;
});
但是很多大型应用HTTP服务都是从MethodChanenl走到Native发送出去的,因此如果HTTP服务都需要自己MOCK,那单测写死的心都有了,在我上一篇文章介绍Flutter 构建PlayGround极速方案有介绍如何HOOK MethodChanenl,并且在宿主APP开启一个网络服务能力,我们完全可以使用CURL将Channel的服务打到宿主APP上,然后通过此方式就可以快速MOCK出任何Channel服务能力;
个人已经实现一个flutter 2.5.x版本的插件方案,欢迎白嫖flutter_mock_service
3. 扩展
本文主要介绍了在FlutterTest环境下如何通过CURL方案可以HOOK住 HTTP服务以及MethodChannel服务,但是flutter_mock_service更多细节我还没介绍,等后续在开坑介绍~
网友评论