[Flutter] 테스트 커버리지

2023-03-18 hit count image

Flutter에서 테스트 커버리지 생성하고 테스트 커버리지를 확인하여 테스트 코드가 작성되지 않는 부분을 찾는 방법에 대해서 알아봅시다.

개요

Flutter로 앱을 개발하면 자연스럽게 테스트 코드를 작성하게 됩니다. 이렇게, 작성한 테스트 코드가 개발한 코드의 모든 부분을 테스트하는지 알아보기 위해, 테스트 커버리지(Test coverage)를 확인하게 됩니다.

이번 블로그 포스트에서는 Flutter에서 테스트 커버리지를 확인하는 방법에 대해서 알아보도록 하겠습니다.

테스트 커버리지

Flutter는 기본적으로 테스트 커버리지 기능을 제공합니다. 다음 명령어를 실행하여 테스트 커버리지를 생성할 수 있습니다.

flutter test --coverage

명령어를 실행하면 다음과 같이 테스트가 실행되고, ./coverage/lcov.info 파일이 생성되는 것을 확인할 수 있습니다.

00:07 +27: All tests passed!

./coverage/lcov.info 파일을 열어보면, 다음과 같은 결과를 확인할 수 있습니다.

SF:lib/controllers/splash_controller.dart
DA:6,6
DA:11,3
DA:13,1
DA:15,2
DA:18,2
DA:19,2
LF:6
LH:6
...

lcov 설치

Flutter는 기본적으로 테스트 커버리지 기능을 제공하며, 테스트 커버리지 결과가 ./coverage/lcov.info 파일 형태로 저장되는 것을 확인하였습니다. 하지만, 해당 파일의 내용은 쉽게 이해할 수 있는 형태가 아닙니다.

여기서 lcov를 사용하면 Flutter 테스트 커버리지로 생성한 lcov.info 파일을 HTML로 변환하는 것이 가능합니다.

다음 명령어를 실행하여 lcov를 설치합니다.

  • macOS: brew install lcov
  • Windows: choco install lcov

HTML로 변환

이제 다음 명령어를 실행하여 ./coverage/lcov.info 파일을 lcov를 사용하여 HTML로 변환시켜 봅니다.

genhtml coverage/lcov.info -o coverage/html

그럼 다음과 같이 HTML 파일을 생성하는 것을 확인할 수 있습니다.

Writing .css and .png files.
Generating output.
Processing file lib/main.dart
Processing file lib/controllers/splash_controller.dart
Processing file lib/controllers/app_web_view_controller.dart
Processing file lib/controllers/home_screen_controller.dart
Processing file lib/screens/home_screen.dart
Processing file lib/widgets/drawer_sub_menu.dart
Processing file lib/widgets/app_drawer.dart
Processing file lib/widgets/app_drawer_header.dart
Processing file lib/widgets/app_header.dart
Processing file lib/widgets/drawer_group_title.dart
Processing file lib/widgets/right_icon_menu_button.dart
Processing file lib/widgets/drawer_bottom_button.dart
Processing file lib/widgets/drawer_main_menu.dart
Writing directory view page.
Overall coverage rate:
  lines......: 100.0% (184 of 184 lines)
  functions..: no data found

또한, ./coverage/html/ 폴더가 생성되고 결과 파일들이 저장된 것을 확인할 수 있습니다.

확인

이제 ./coverage/html/index.html 파일을 열어봅니다. 저는 macOS를 사용하기 때문에 다음 명령어를 사용하여 해당 파일을 열었습니다.

open ./coverage/html/index.html

파일을 열면 다음과 같이 파일별 테스트 커버리지를 확인할 수 있습니다.

Flutter - test coverage file list

링크를 클릭해서 해당 파일을 열면 다음과 같이 테스트 커버리지를 상세하게 확인할 수 있습니다.

Flutter - test coverage details

.gitignore

Flutter의 테스트 커버리지 기능으로 생성한 lcov.info 파일과 lcov로 생성한 HTML 파일등은 Git으로 버전 관리를 할 필요없이 그때그때 생성하여 확인하면 됩니다.

따라서 .gitignore 파일을 열고 다음과 같이 coverage 폴더를 추가하여 테스트 커버리지와 관련된 파일들을 버전 관리하지 않도록 설정합니다.

...
coverage/
...

bin/coverage.dart

지금까지 Flutter에서 테스트 커버리지를 생성하고 lcov를 사용하여 HTML로 변환하고, 변환한 HTML 파일을 열어서 테스트 커버리지를 확인하는 방법에 대해서 알아보았습니다.

저는 이런 명령어를 한번에 실행하기 위해서, ./bin/coverage.dart 파일을 생성하고 다음과 같이 수정하여 사용하고 있습니다.

// ignore_for_file: avoid_print
import 'dart:io';

void main(List<String> arguments) async {
  await execute('flutter test --coverage');
  await execute('genhtml coverage/lcov.info -o coverage/html');
  await execute('open coverage/html/index.html');
}

Future<void> execute(String cmd, {String? dir, bool skipError = false}) async {
  print(cmd + (dir != null ? ' [on $dir]' : ''));

  var args = cmd.split(' ');
  var command = args.first;
  var options = args.length > 1
      ? args.getRange(1, args.length).toList()
      : [] as List<String>;

  var result = await Process.run(
    command,
    options,
    workingDirectory: dir,
  );

  print(result.stdout);
  if (!skipError && result.stderr != '') {
    throw Exception(result.stderr);
  }
}

이렇게 생성한 파일은 다음 명령어를 실행하여 실행할 수 있습니다.

dart run :coverage

저는 macOS 사용자이기 때문에, Windows 사용자는 Windows에 맞게 해당 명령어를 수정하여 사용해야 합니다.

void main(List<String> arguments) async {
  await execute('flutter test --coverage');
  await execute('genhtml coverage/lcov.info -o coverage/html');
  await execute('open coverage/html/index.html');
}

완료

이것으로 Flutter에서 테스트 커버리지를 확인하는 방법에 대해서 알아보았습니다. 테스트 커버리지가 100%라고 해서 모든 코드에 대한 테스트 케이스를 작성했다고는 할 수 없지만, 테스트 커버리지를 통해 테스트가 작성되지 않은 코드를 확인할 수 있으므로, 테스트 코드 작성에 큰 도움이 됩니다.

제 블로그가 도움이 되셨나요? 하단의 댓글을 달아주시면 저에게 큰 힘이 됩니다!

앱 홍보

책 홍보

블로그를 운영하면서 좋은 기회가 생겨 책을 출판하게 되었습니다.

아래 링크를 통해 제가 쓴 책을 구매하실 수 있습니다.
많은 분들에게 도움이 되면 좋겠네요.

스무디 한 잔 마시며 끝내는 React Native, 비제이퍼블릭
스무디 한 잔 마시며 끝내는 리액트 + TDD, 비제이퍼블릭
[심통]현장에서 바로 써먹는 리액트 with 타입스크립트 : 리액트와 스토리북으로 배우는 컴포넌트 주도 개발, 심통
Posts