티스토리 뷰

Flutter 앱 개발에서 성능은 사용자 경험에 직결되는 핵심 요소입니다. 특히 통합 테스트와 성능 프로파일링을 결합하면, 실제 사용자 환경에서의 성능 문제를 미리 발견하고 해결할 수 있습니다. 이번 포스트에서는 Flutter 통합 테스트에서 성능 프로파일링을 구현하는 방법과 이를 통해 얻을 수 있는 이점을 심도 있게 다뤄보겠습니다.

참고. Measure performance with an integration test

성능 프로파일링이란?

성능 프로파일링은 애플리케이션이 실행되는 동안 리소스 사용, 응답 시간, 프레임 속도 등의 주요 성능 데이터를 수집하고 분석하는 과정입니다. 이를 통해 성능 병목 현상을 찾아내고, 앱의 실행 효율성을 개선할 수 있습니다.

Flutter에서 성능 프로파일링의 목적

  1. FPS(Frame Per Second) 최적화
    앱의 렌더링 성능을 분석하여 화면 전환 및 애니메이션 부드러움을 보장.
  2. CPU 및 메모리 사용 분석
    불필요한 자원 소비를 파악하고 최적화 방안을 모색.
  3. 네트워크 요청 속도 확인
    API 응답 시간 및 데이터 처리 성능 개선.

통합 테스트와 성능 프로파일링의 연계

통합 테스트와 성능 프로파일링을 결합하면 앱의 주요 흐름을 테스트하면서 동시에 성능 데이터를 수집할 수 있습니다. 이는 단순히 기능적 오류를 찾는 것을 넘어, 실제 사용자 환경에서의 성능 최적화를 가능하게 합니다.

Flutter에서 성능 프로파일링 구현 방법

1. 의존성 추가

pubspec.yaml에 다음과 같은 패키지를 추가합니다:

dev_dependencies:
  integration_test:
    sdk: flutter

추가 후 flutter pub get 명령어를 실행합니다.

2. 통합 테스트 구성

테스트 드라이버 작성

test_driver/integration_test_driver.dart 파일을 생성하고 아래 코드를 작성합니다:

import 'package:integration_test/integration_test_driver_extended.dart';

Future<void> main() => integrationDriver();
테스트 파일 작성

integration_test/app_test.dart 파일에 아래 코드를 추가합니다:

import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:your_app/main.dart' as app;

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  testWidgets('홈 화면 로딩 성능 측정', (WidgetTester tester) async {
    app.main();
    await tester.pumpAndSettle();

    final Stopwatch stopwatch = Stopwatch()..start();

    // 특정 위젯 확인
    expect(find.text('Welcome'), findsOneWidget);

    stopwatch.stop();
    print('로딩 시간: ${stopwatch.elapsedMilliseconds}ms');
  });
}

3. 성능 데이터 수집 및 분석

성능 데이터 수집

테스트 실행 시 다음 명령어로 성능 데이터를 수집합니다:

flutter drive --driver=test_driver/integration_test_driver.dart --target=integration_test/app_test.dart --profile
프로파일링 데이터 분석

결과는 JSON 형식으로 저장되며, 이를 Flutter DevTools 또는 기타 데이터 분석 도구를 활용해 시각화할 수 있습니다.

성능 최적화를 위한 팁

  1. 느린 렌더링 해결
    • debugProfileBuildsEnableddebugProfilePaintsEnabled를 사용해 렌더링 문제를 확인합니다.
  2. 네트워크 호출 최적화
    • dio 패키지와 같은 HTTP 클라이언트를 활용하여 요청 시간을 측정하고 최적화합니다.
  3. Flutter DevTools 활용
    • DevTools를 사용해 CPU, 메모리, 프레임 속도 데이터를 상세히 분석합니다.
  4. Jank(프레임 끊김) 최소화
    • shouldRebuild 메서드를 적절히 사용하여 불필요한 위젯 재구성을 방지합니다.

통합 테스트와 성능 프로파일링의 실질적 이점

  • 실제 사용자 경험 개선
    사용자 흐름을 따라 테스트하면서 성능 병목 현상을 제거.
  • 효율적인 자원 관리
    CPU 및 메모리 사용을 분석하여 불필요한 낭비 제거.
  • 빠른 문제 발견 및 수정
    문제를 사전에 파악해 유지보수 비용 절감.

결론

Flutter 통합 테스트와 성능 프로파일링은 단순히 오류를 찾는 것을 넘어, 사용자 경험을 개선하고 앱의 실행 효율성을 극대화할 수 있는 강력한 도구입니다. 위 가이드를 따라 프로젝트에 통합하고, 더 나은 Flutter 앱을 만들어보세요.

 

// 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'] as Map<String, dynamic>,
        );

        // 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,
        );
      }
    },
  );
}