[MOBILE-009][중급] 화면 동작을 자동으로 확인하기
페이지 정보

본문
[이번 수업]
모바일 앱은 화면 크기, 운영체제, 권한과 네트워크 상태가 달라 수동 확인만으로 회귀 버그를 막기 어렵습니다. 회귀 버그는 고친 기능이 다음 변경에서 다시 깨지는 문제입니다. 이번에는 작은 화면 테스트를 자동 실행하고 테스트 범위를 나누는 법을 배웁니다.
[선수지식]
MOBILE-003의 화면·컴포넌트, MOBILE-004의 상태, SWE-003의 단위·통합 테스트를 알면 좋습니다. Flutter SDK가 설치된 로컬 환경을 사용합니다.
[학습목표]
1. 단위·컴포넌트·통합·UI 테스트를 구분합니다.
2. 버튼을 찾아 누르고 화면 변화를 검증합니다.
3. 실제 기기 시험이 필요한 경계를 설명합니다.
[핵심개념]
단위 테스트는 함수나 상태 변환을 빠르게 확인합니다. 컴포넌트 테스트는 한 화면 조각의 표시와 입력을 검사합니다. 통합 테스트는 저장소, 화면, 서비스가 함께 동작하는 중요한 흐름을 확인하고, UI 테스트는 실행된 앱을 사용자처럼 조작합니다. 범위가 커질수록 실제 환경과 비슷해지지만 느리고 실패 원인을 찾기 어려워집니다. 작은 테스트를 많이 두고 로그인·결제 같은 핵심 흐름만 큰 테스트로 보완합니다.
모바일에서는 화면 크기와 방향, 운영체제 버전, 오프라인, 권한 거부와 앱 재시작도 시험 목록에 넣습니다. 모든 조합을 매번 돌리기보다 위험이 큰 대표 조합을 변경 전 검사에 넣고 더 넓은 기기 조합은 정기 실행합니다.
화면 요소는 좌표보다 안정된 Key나 접근성 식별자로 찾습니다. 고정된 몇 초를 기다리는 대신 화면이 원하는 상태가 될 때까지 기다립니다. 시간, 난수, 네트워크 응답은 테스트에서 통제하고 각 테스트가 독립된 초기 상태에서 시작하게 합니다.
[따라하기]
터미널에서 `flutter create --empty mobile_test_demo`를 실행한 뒤, 생성된 `test/widget_test.dart`를 아래 내용으로 바꿉니다.
```dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
class SaveButton extends StatefulWidget {
const SaveButton({super.key});
@override
State<SaveButton> createState() => _SaveButtonState();
}
class _SaveButtonState extends State<SaveButton> {
bool saved = false;
@override
Widget build(BuildContext context) {
return ElevatedButton(
key: const Key('save_button'),
onPressed: () => setState(() => saved = true),
child: Text(saved ? '저장됨' : '저장'),
);
}
}
void main() {
testWidgets('저장 버튼의 상태가 바뀐다', (tester) async {
await tester.pumpWidget(
const MaterialApp(home: Scaffold(body: SaveButton())),
);
expect(find.text('저장'), findsOneWidget);
await tester.tap(find.byKey(const Key('save_button')));
await tester.pump();
expect(find.text('저장됨'), findsOneWidget);
});
}
```
macOS·Linux·Windows PowerShell 모두 프로젝트 폴더에서 `flutter test test/widget_test.dart`를 실행합니다. 첫 실행은 의존성을 준비해 더 오래 걸릴 수 있습니다. 예상 결과의 핵심은 다음과 같습니다.
```text
00:00 +1: All tests passed!
```
이 테스트는 실제 기기 없이 단순한 테스트 화면에서 버튼 탭과 다시 그리기를 확인합니다. 카메라, 알림, 생체 인증처럼 운영체제 기능과 연결된 흐름은 에뮬레이터와 허가된 실제 기기에서도 확인해야 합니다.
[흔한 실수]
문구나 좌표에만 의존하면 작은 디자인 변경에도 테스트가 깨집니다. 여러 테스트가 같은 계정과 저장 데이터를 공유하거나 고정 대기 시간을 쓰면 간헐적으로 실패합니다. 화면 테스트 수만 늘리고 중요한 상태 변환의 단위 테스트를 빼먹지 마세요.
[보안 주의]
본인 소유의 에뮬레이터·기기와 격리된 시험 서버만 사용합니다. 실제 개인정보, 운영 계정, 결제 수단과 비밀키를 테스트 데이터에 넣지 않습니다. 실패 화면·동영상·로그에도 입력값이 남을 수 있으므로 접근 권한과 보관 기간을 제한합니다. 인증을 건너뛰는 시험용 기능이 배포 앱에 포함되지 않도록 빌드 설정을 검사합니다.
[직접 해볼 과제]
저장 버튼을 한 번 더 눌렀을 때 `저장됨`이 유지되는 검증을 추가하세요. 이어서 버튼 Key를 제거해 테스트가 왜 불안정해지는지 비교하고 다시 복구합니다.
[확인문제]
1. 단위 테스트를 큰 UI 테스트보다 많이 두는 이유는 무엇인가요?
2. 화면 요소를 좌표 대신 Key로 찾으면 어떤 점이 좋아지나요?
3. 실제 기기 시험이 꼭 필요한 기능에는 무엇이 있나요?
[다음 학습]
다음 과정 IOT-009에서는 펌웨어 업데이트와 장치 보안을 배웁니다. MOBILE 트랙은 배터리·메모리·네트워크 성능으로 이어집니다.
[공식 참고 자료]
- 모바일 프레임워크 테스트 개요: https://docs.flutter.dev/testing/overview
- 컴포넌트 테스트 공식 예제: https://docs.flutter.dev/cookbook/testing/widget/introduction
- 통합 테스트 공식 안내: https://docs.flutter.dev/testing/integration-tests
- Android 테스트 전략: https://developer.android.com/training/testing/fundamentals/strategies
- iOS UI 테스트 프레임워크: https://developer.apple.com/documentation/xctest
모바일 앱은 화면 크기, 운영체제, 권한과 네트워크 상태가 달라 수동 확인만으로 회귀 버그를 막기 어렵습니다. 회귀 버그는 고친 기능이 다음 변경에서 다시 깨지는 문제입니다. 이번에는 작은 화면 테스트를 자동 실행하고 테스트 범위를 나누는 법을 배웁니다.
[선수지식]
MOBILE-003의 화면·컴포넌트, MOBILE-004의 상태, SWE-003의 단위·통합 테스트를 알면 좋습니다. Flutter SDK가 설치된 로컬 환경을 사용합니다.
[학습목표]
1. 단위·컴포넌트·통합·UI 테스트를 구분합니다.
2. 버튼을 찾아 누르고 화면 변화를 검증합니다.
3. 실제 기기 시험이 필요한 경계를 설명합니다.
[핵심개념]
단위 테스트는 함수나 상태 변환을 빠르게 확인합니다. 컴포넌트 테스트는 한 화면 조각의 표시와 입력을 검사합니다. 통합 테스트는 저장소, 화면, 서비스가 함께 동작하는 중요한 흐름을 확인하고, UI 테스트는 실행된 앱을 사용자처럼 조작합니다. 범위가 커질수록 실제 환경과 비슷해지지만 느리고 실패 원인을 찾기 어려워집니다. 작은 테스트를 많이 두고 로그인·결제 같은 핵심 흐름만 큰 테스트로 보완합니다.
모바일에서는 화면 크기와 방향, 운영체제 버전, 오프라인, 권한 거부와 앱 재시작도 시험 목록에 넣습니다. 모든 조합을 매번 돌리기보다 위험이 큰 대표 조합을 변경 전 검사에 넣고 더 넓은 기기 조합은 정기 실행합니다.
화면 요소는 좌표보다 안정된 Key나 접근성 식별자로 찾습니다. 고정된 몇 초를 기다리는 대신 화면이 원하는 상태가 될 때까지 기다립니다. 시간, 난수, 네트워크 응답은 테스트에서 통제하고 각 테스트가 독립된 초기 상태에서 시작하게 합니다.
[따라하기]
터미널에서 `flutter create --empty mobile_test_demo`를 실행한 뒤, 생성된 `test/widget_test.dart`를 아래 내용으로 바꿉니다.
```dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
class SaveButton extends StatefulWidget {
const SaveButton({super.key});
@override
State<SaveButton> createState() => _SaveButtonState();
}
class _SaveButtonState extends State<SaveButton> {
bool saved = false;
@override
Widget build(BuildContext context) {
return ElevatedButton(
key: const Key('save_button'),
onPressed: () => setState(() => saved = true),
child: Text(saved ? '저장됨' : '저장'),
);
}
}
void main() {
testWidgets('저장 버튼의 상태가 바뀐다', (tester) async {
await tester.pumpWidget(
const MaterialApp(home: Scaffold(body: SaveButton())),
);
expect(find.text('저장'), findsOneWidget);
await tester.tap(find.byKey(const Key('save_button')));
await tester.pump();
expect(find.text('저장됨'), findsOneWidget);
});
}
```
macOS·Linux·Windows PowerShell 모두 프로젝트 폴더에서 `flutter test test/widget_test.dart`를 실행합니다. 첫 실행은 의존성을 준비해 더 오래 걸릴 수 있습니다. 예상 결과의 핵심은 다음과 같습니다.
```text
00:00 +1: All tests passed!
```
이 테스트는 실제 기기 없이 단순한 테스트 화면에서 버튼 탭과 다시 그리기를 확인합니다. 카메라, 알림, 생체 인증처럼 운영체제 기능과 연결된 흐름은 에뮬레이터와 허가된 실제 기기에서도 확인해야 합니다.
[흔한 실수]
문구나 좌표에만 의존하면 작은 디자인 변경에도 테스트가 깨집니다. 여러 테스트가 같은 계정과 저장 데이터를 공유하거나 고정 대기 시간을 쓰면 간헐적으로 실패합니다. 화면 테스트 수만 늘리고 중요한 상태 변환의 단위 테스트를 빼먹지 마세요.
[보안 주의]
본인 소유의 에뮬레이터·기기와 격리된 시험 서버만 사용합니다. 실제 개인정보, 운영 계정, 결제 수단과 비밀키를 테스트 데이터에 넣지 않습니다. 실패 화면·동영상·로그에도 입력값이 남을 수 있으므로 접근 권한과 보관 기간을 제한합니다. 인증을 건너뛰는 시험용 기능이 배포 앱에 포함되지 않도록 빌드 설정을 검사합니다.
[직접 해볼 과제]
저장 버튼을 한 번 더 눌렀을 때 `저장됨`이 유지되는 검증을 추가하세요. 이어서 버튼 Key를 제거해 테스트가 왜 불안정해지는지 비교하고 다시 복구합니다.
[확인문제]
1. 단위 테스트를 큰 UI 테스트보다 많이 두는 이유는 무엇인가요?
2. 화면 요소를 좌표 대신 Key로 찾으면 어떤 점이 좋아지나요?
3. 실제 기기 시험이 꼭 필요한 기능에는 무엇이 있나요?
[다음 학습]
다음 과정 IOT-009에서는 펌웨어 업데이트와 장치 보안을 배웁니다. MOBILE 트랙은 배터리·메모리·네트워크 성능으로 이어집니다.
[공식 참고 자료]
- 모바일 프레임워크 테스트 개요: https://docs.flutter.dev/testing/overview
- 컴포넌트 테스트 공식 예제: https://docs.flutter.dev/cookbook/testing/widget/introduction
- 통합 테스트 공식 안내: https://docs.flutter.dev/testing/integration-tests
- Android 테스트 전략: https://developer.android.com/training/testing/fundamentals/strategies
- iOS UI 테스트 프레임워크: https://developer.apple.com/documentation/xctest
- 이전글[IOT-009][중급] 펌웨어를 안전하게 업데이트하기 26.09.04
- 다음글[SWE-009][중급] 느린 코드를 측정하고 빠르게 고치기 26.09.04
댓글목록
등록된 댓글이 없습니다.
