플러터 Testing - Integration(2)

Inyeong Kang·2023년 7월 7일
0
post-thumbnail

Flutter Cookbook 링크

Performance profiling

모바일 앱의 경우 성능은 사용자 경험에 매우 중요하다. 사용자는 앱이 "jank"(쟁크. 화면 버벅거림)로 알려진 끊김이나 건너뛰는 프레임 없이 부드러운 스크롤과 의미 있는 애니메이션을 갖기를 기대한다. 다양한 장치에서 앱에 버벅거림이 없는지 확인하는 방법은 무엇일까?

두 가지 옵션이 있다. 먼저 다른 기기에서 앱을 수동으로 테스트한다. 이 접근 방식은 보다 작은 앱에 적합할 수 반면에 앱 크기가 커지면 더 번거로워진다. 또는 특정 작업을 수행하고 성능 타임라인을 기록하는 통합 테스트를 실행한다. 그런 다음 결과를 검토하여 앱의 특정 섹션을 개선해야 하는지 여부를 결정한다.

이 레시피에서는 특정 작업을 수행하는 동안 성능 타임라인을 기록하고 결과 요약을 로컬 파일에 저장하는 테스트를 작성하는 방법을 알아보자.

이 레시피는 다음 단계를 사용한다.
1. 항목 목록을 스크롤하는 테스트 작성
2. 앱의 성능 기록
3. 결과를 디스크에 저장
4. 테스트 실행
5. 결과 검토

1. 항목 목록을 스크롤하는 테스트 작성

이 레시피에서는 항목 목록을 스크롤할 때 앱의 성능을 기록한다. 성능 프로파일링에 집중하기 위해 이 레시피는 위젯 테스트의 스크롤 레시피를 기반으로 한다.

해당 레시피의 지침에 따라 앱을 만들고 테스트를 작성하여 모든 것이 예상대로 작동하는지 확인한디.

2. 앱의 성능 기록

다음으로 목록을 스크롤하면서 앱의 성능을 기록한다. IntegrationTestWidgetsFlutterBinding 클래스에서 제공하는 traceAction() 메소드를 사용하여 이 작업을 수행한다.

이 메서드는 제공된 기능을 실행하고 앱의 성능에 대한 자세한 정보와 함께 Timeline을 기록한다. 이 예제는 특정 항목이 표시되도록 항목 목록을 스크롤하는 기능을 제공한다. 함수가 완료되면 traceAction()는 Timeline을 포함한 보고 데이터 Map을 생성한다.

하나 이상의 traceAction을 실행할 때 reportKey를 지정해라. 기본적으로 모든 Timelines는 주요 Timeline을 저장와 함께 저장되며 예시에서 reportKey가 scrolling_timeline으로 변경된다.

await binding.traceAction(
  () async {
    // Scroll until the item to be found appears.
    await tester.scrollUntilVisible(
      itemFinder,
      500.0,
      scrollable: listFinder,
    );
  },
  reportKey: 'scrolling_timeline',
);
  • traceAction 메서드: action을 수행하고 성능 추적 출력. 추적을 중지하기 전에 완료된 action에 의해 반환된 Future를 대기.

3. 결과를 디스크에 저장

이제 성능 타임라인을 캡처했으므로 이를 검토할 방법이 필요하다. Timeline 객체는 발생한 모든 이벤트에 대한 자세한 정보를 제공하지만 결과를 검토하는 편리한 방법은 제공하지 않는다.

따라서 를 Timeline를 TimelineSummary로 변환해라. TimelineSummary는 결과를 보다 쉽게 검토할 수 있는 두 가지 작업을 수행할 수 있다.
1. Timeline이 포함된 데이터를 요약하는 json 문서를 디스크에 작성한다. 요약에는 건너뛴 프레임 수, 가장 느린 빌드 시간 등에 대한 정보가 포함된다.
2. Timeline을 디스크에 json 파일로 저장한다. 이 파일은 chrome://tracing에 있는 Chrome 브라우저의 추적 도구로 열 수 있다.
결과를 캡처하려면 test_driver 폴더에 perf_driver.dart 라고 지정된 파일을 생성하고 아래 코드를 추가한다.

import 'package:flutter_driver/flutter_driver.dart' as driver;
import 'package:integration_test/integration_test_driver.dart';

Future<void> main() {
  return integrationDriver(
    responseDataCallback: (data) async {
      if (data != null) {
        final timeline = driver.Timeline.fromJson(data['scrolling_timeline']);

        // Convert the Timeline into a TimelineSummary that's easier to
        // read and understand.
        final summary = driver.TimelineSummary.summarize(timeline);

        // Then, write the entire timeline to disk in a json format.
        // This file can be opened in the Chrome browser's tracing tools
        // found by navigating to chrome://tracing.
        // Optionally, save the summary to disk by setting includeSummary
        // to true
        await summary.writeTimelineToFile(
          'scrolling_timeline',
          pretty: true,
          includeSummary: true,
        );
      }
    },
  );
}

이 integrationDriver기능에는 사용자 정의할 수 있는 responseDataCallback이 있다. 기본적으로 결과를 integration_response_data.json 파일에 기록 하지만 이 예제와 같이 요약을 생성하도록 사용자 정의할 수 있다.

4. 테스트 실행

성능 Timeline을 캡처 하고 결과 요약을 디스크에 저장하도록 테스트를 구성한 후, 다음 명령을 사용하여 테스트를 실행한다.
flutter drive \ --driver=test_driver/perf_driver.dart \ --target=integration_test/scrolling_test.dart \ --profile
이 --profile옵션은 "디버그 모드"가 아닌 "프로필 모드"용으로 앱을 컴파일하여 벤치마크 결과가 최종 사용자가 경험하게 되는 것과 더 가깝다는 것을 의미한다.
참고) 모바일 장치 또는 에뮬레이터에서 실행할 때 --no-dds 명령어를 실행하자. 이 옵션은 컴퓨터에서 액세스할 수 없는 DDS(Dart Development Service)를 비활성화한다.

5. 결과 검토

테스트가 성공적으로 완료되면 프로젝트 루트의 build 디렉터리에 두 개의 파일이 포함된다.

  1. scrolling_summary.timeline_summary.json은 요약을 포함한다. 포함된 정보를 검토하려면 텍스트 편집기로 파일을 현다. 고급 설정을 사용하면 테스트가 실행될 때마다 요약을 저장하고 결과 그래프를 만들 수 있다.
  2. scrolling_timeline.timeline.json은 전체 타임라인 데이터를 포함한다. chrome://tracing에 있는 Chrome 브라우저의 추적 도구를 사용하여 파일을 연다. 추적 도구는 타임라인 데이터를 검사하여 성능 문제의 원인을 발견할 수 있는 편리한 인터페이스를 제공한다.
  • Summary example
{
  "average_frame_build_time_millis": 4.2592592592592595,
  "worst_frame_build_time_millis": 21.0,
  "missed_frame_build_budget_count": 2,
  "average_frame_rasterizer_time_millis": 5.518518518518518,
  "worst_frame_rasterizer_time_millis": 51.0,
  "missed_frame_rasterizer_budget_count": 10,
  "frame_count": 54,
  "frame_build_times": [
    6874,
    5019,
    3638
  ],
  "frame_rasterizer_times": [
    51955,
    8468,
    3129
  ]
}

완성된 예제

  • integration_test/scrolling_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

import 'package:scrolling/main.dart';

void main() {
  final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  testWidgets('Counter increments smoke test', (tester) async {
    // Build our app and trigger a frame.
    await tester.pumpWidget(MyApp(
      items: List<String>.generate(10000, (i) => 'Item $i'),
    ));

    final listFinder = find.byType(Scrollable);
    final itemFinder = find.byKey(const ValueKey('item_50_text'));

    await binding.traceAction(
      () async {
        // Scroll until the item to be found appears.
        await tester.scrollUntilVisible(
          itemFinder,
          500.0,
          scrollable: listFinder,
        );
      },
      reportKey: 'scrolling_timeline',
    );
  });
}
  • test_driver/perf_driver.dart
import 'package:flutter_driver/flutter_driver.dart' as driver;
import 'package:integration_test/integration_test_driver.dart';

Future<void> main() {
  return integrationDriver(
    responseDataCallback: (data) async {
      if (data != null) {
        final timeline = driver.Timeline.fromJson(data['scrolling_timeline']);

        // Convert the Timeline into a TimelineSummary that's easier to
        // read and understand.
        final summary = driver.TimelineSummary.summarize(timeline);

        // Then, write the entire timeline to disk in a json format.
        // This file can be opened in the Chrome browser's tracing tools
        // found by navigating to chrome://tracing.
        // Optionally, save the summary to disk by setting includeSummary
        // to true
        await summary.writeTimelineToFile(
          'scrolling_timeline',
          pretty: true,
          includeSummary: true,
        );
      }
    },
  );
}
profile
안녕하세요. 강인영입니다. GDSC에서 필요한 것들을 작업하고 업로드하려고 합니다!

0개의 댓글