[Flutter] 통합 테스트(Integration Test)

2021-06-06 hit count image

이번 블로그 포스트에서는 Flutter에서 통합 테스트(Integration Test)를 하는 방법에 대해서 알아봅시다.

개요

Flutter에서 개발한 앱의 통합 테스트(Integration Test)를 하는 방법에 대해서 알아보려고 합니다. Flutter의 공식 문서에서도 사용법이 자세히 나와 있으니 참고하시기 바랍니다.

이번 블로그는 공식 문서의 내용을 참고하였으며, 통합 테스트를 하기 위한 내용을 정리하였습니다. 이곳에서 소개하는 소스코드는 아래에 링크에서 확인할 수 있습니다.

integration_test 패키지 설치

Flutter에서 통합 테스트를 하기 위해서는 integration_test 패키지를 사용할 필요가 있습니다. Flutter SDK를 설치하면 해당 패키지도 같이 설치되므로 따로 설치를 할 필요는 없습니다.

다만, 해당 패키지를 사용하기 위해 pubspec.yaml 파일을 다음과 같이 수정할 필요가 있습니다.

...
dev_dependencies:
  flutter_test:
    sdk: flutter
  integration_test:
    sdk: flutter
...

설정

통합 테스트는, 안드로이드의 에뮬레이터나 iOS의 시뮬레이터, 또는 디바이스에서 실제로 앱을 실행시킨 후, 테스트 시나리오대로 테스트를 진행하게 됩니다. 따라서 integration_test 패키지를 사용하여 Flutter에서 통합 테스트를 하기 위해서는, 각 OS에 맞는 설정을 할 필요가 있습니다.

안드로이드 설정

이제 integration_test 패키지를 사용하여 Flutter에서 통합 테스트를 하기 위해 안드로이드를 설정하는 방법에 대해서 알아봅시다.

  1. ./android/app/build.gradle 파일을 열고 다음과 같이 수정합니다.
  ...
  defaultConfig {
      ...
      testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
  }
  ...
  dependencies {
      ...
      // For integration test
      testImplementation 'junit:junit:4.12'
      // https://developer.android.com/jetpack/androidx/releases/test/#1.2.0
      androidTestImplementation 'androidx.test:runner:1.2.0'
      androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
  }
  ...
  1. ./android/app/src/androidTest/java/com/example/[Project Name]/MainActivityTest.java 파일을 생성하고 다음과 같이 수정합니다.(Project Name 부분을 자신의 Flutter 프로젝트 이름으로 변경합니다.)
  package com.example.[Project Name];

  import androidx.test.rule.ActivityTestRule;
  import dev.flutter.plugins.integration_test.FlutterTestRunner;
  import org.junit.Rule;
  import org.junit.runner.RunWith;

  @RunWith(FlutterTestRunner.class)
  public class MainActivityTest {
    @Rule
    public ActivityTestRule<MainActivity> rule = new ActivityTestRule<>(MainActivity.class, true, false);
  }

iOS 설정

  1. ios/Runner.xcworkspace 파일을 실행하여 Xcode를 실행합니다. (다음 명령어를 실행하여 Xcode를 실행할 수 있습니다.)
  open ./ios/Runner.xcworkspace
  1. File > New > Target...을 선택합니다.

Flutter integration test - create new target

  1. Unit Testing Bundle 검색하고 Next 버튼을 클릭합니다.

Flutter integration test - unit testing bundle

  1. Product NameRunnerTests를 입력합니다. Organization Identifier를 입력합니다. LanguageObjective-C를 변경합니다. 그리고 Finish를 선택하여 Unit Testing Bundle을 생성합니다.

Flutter integration test - unit testing

  1. Runner > Info > Configurations를 선택하고 Debug/Release/Profile 항목에서 RunnerRunnerTests의 설정값을 동일한 값으로 맞춰줍니다.

Flutter integration test - info configurations

  1. Runner > Build SettingsiOS Deployment TargetRunnerTests > Build SettingsiOS Deployment Target을 동일한 버전으로 맞춰줍니다.

Flutter integration test - info configurationsFlutter integration test - info configurations

  1. ./ios/Podfile 파일을 열고 다음과 같이 수정합니다.
  platform :ios, '10.0'
  ...
  target 'Runner' do
    ...
    # For integration test
    target 'RunnerTests' do
      inherit! :search_paths
    end
  end
  ...
  1. 다음 명령어를 실행합니다.
  flutter build ios
  or
  flutter build ios --no-codesign
  1. Xcode에서 RunnerTests.m 파일을 열고 모든 내용을 지우고, 다음의 내용을 추가합니다.
  @import XCTest;
  @import integration_test;

  INTEGRATION_TEST_IOS_RUNNER(RunnerTests)

Flutter integration test - modify RunnerTests.m

  1. Product > Test를 선택하여 테스트를 실행해 봅니다.

Flutter integration test - product test

문제가 없다면, 빌드가 성공하는 것을 확인할 수 있으며 시뮬레이터가 실행되는 것을 확인할 수 있습니다.

테스트 코드 작성

이제 각 OS에서 테스트할 준비가 끝났습니다. 이제 실제로 테스트 코드를 작성해 보도록 합시다.

드라이버

Flutter에서 통합 테스트(Integration Test)를 하기 위해서는 드라이버(Driver)가 필요합니다. ./test_driver/integration_test.dart 파일을 생성하고 다음과 같이 수정합니다.

import 'package:integration_test/integration_test_driver.dart';

Future<void> main() => integrationDriver();

테스트 코드

Flutter에서 통합 테스트(Integration Test)를 작성하기 위해서는 integration_test라는 폴더를 생성할 필요가 있으며, 유닛 테스트와 마찬가지로 _test.dart 형식으로 테스트 파일을 생성할 필요가 있습니다. 여기서는 우선 ./integration_test/main_test.dart 파일을 생성하고 다음과 같이 수정하였습니다.

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

import 'package:integration_test_example/main.dart' as app;

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  testWidgets("successful test example", (WidgetTester tester) async {
    app.main();
    await tester.pumpAndSettle();

    expect(find.text('0'), findsOneWidget);

    await tester.tap(find.byType(FloatingActionButton));
    await tester.pumpAndSettle();

    expect(find.text('1'), findsOneWidget);
  });
}

스크롤

스크롤이 있는 화면에서 통합 테스트를 할 때, 화면에 보이지 않는 위젯을 누르면, 에러가 발생합니다. 따라서 해당 위젯이 화면에 보일 때까지, 화면을 스크롤할 필요가 있습니다.

통합 테스트에서 화면을 스크롤할 때, 다음과 같은 코드를 사용합니다.

...
await tester.scrollUntilVisible(find.text('Cancel'), -40);
...

위의 통합 테스트 코드는 Cancel이라는 글자가 보일때까지, 스크롤을 40px씩 이동시킵니다.

테스트 코드 실행

그럼 이렇게 작성한 테스트 코드를 실행해 봅시다.

안드로이드 통합 테스트

안드로이드 통합 테스트를 하기 위해서는 안드로이드 에뮬레이터를 실행할 필요가 있습니다. 다음 명령어를 사용하여 실행 가능한 안드로이드 에뮬레이터를 확인합니다.

emulator -list-avds

다음 명령어를 사용하여 에뮬레이터를 실행합니다. & 마크는 명령어를 백그라운드에서 실행하기 위한 옵션입니다.

emulator -avd [Emulator ID] &

에뮬레이터가 실행되었다면, 다음 명령어를 실행하여 작성한 통합 테스트를 실행합니다.

flutter test integration_test/

그럼 에뮬레이터에서 우리가 작성한 통합 테스트가 실행되는 것을 확인할 수 있습니다. 모든 테스트가 무사히 성공하였다면, 다음 명령어를 실행하여 에뮬레이터를 종료시킵니다.

adb emu kill

iOS 통합 테스트

다음 명령어를 실행하여 최근 실행한 iOS 시뮬레이터를 실행합니다.

open -a Simulator.app

시뮬레이터가 실행되었다면, 다음 명령어를 실행하여 통합 테스트를 실행합니다.

flutter test integration_test/

작성한 통합 테스트가 모두 성공하였다면, 다음 명령어를 실행하여, 실행중인 시뮬레이터를 종료시킵니다.

killall "iOS Simulator"

완료

이것으로 Flutter에서 통합 테스트를 하기 위한 준비와, 통합 테스트를 작성하는 방법, 그리고 통합 테스트를 실행하는 방법에 대해서 알아보았습니다. 이제 여러분도 실제 환경에서 여러분의 앱을 테스트해 보시기 바랍니다.

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

책 홍보

스무디 한 잔 마시며 끝내는 React Native 책을 출판한지 벌써 2년이 다되었네요.
이번에도 좋은 기회가 있어서 스무디 한 잔 마시며 끝내는 리액트 + TDD 책을 출판하게 되었습니다.

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

스무디 한 잔 마시며 끝내는 React Native, 비제이퍼블릭
스무디 한 잔 마시며 끝내는 리액트 + TDD, 비제이퍼블릭
Posts