Flutter Test CI通用方案详解

1. 背景

在Flutter Test官方的CI方案中,包含UnitTest/WidgetTest/DriverTest三种模式,其中UnitTest/WidgetTest是可以在代码的沙盒环境下运行,而Driver Test需要依赖整包构建;大家都知道在单元测试过程中发现问题成本最低,而整包构建耗时比较久,因此这里介绍一种通用的Flutter Test在CI阶段的方案;

Flutter CI自动化检测能力主要通过FlutterTest能力建设,但具体数据能力建设稍有不足,主要原因是

    1. FlutterTest不支持直接发送一个http请求功能;
    1. 以及大量的Channel数据需要主动MOCK,如果大型应用需要mock的太多太杂;

同理可以看在stackoverflow上也有很多人咨询过为什么flutter test环境下无法运行一个HTTP服务请求; stackoverflow.com/questions/6…

其实分析主要原因是一个在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命令:

image.png

既然可以运行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更多细节我还没介绍,等后续在开坑介绍~

猜你喜欢

转载自juejin.im/post/7119103230251892743