-
4화. AI를 이용한 통합테스트 코드 작성Archiving/Flutter 2024. 1. 30. 11:07반응형
원래 일지 같은 느낌으로 글을 작성하려고 했던 건데, 어느 순간 강의 글처럼 쓰고 있었다. 안된다.. 이런 생각을 가지면 큰일난다. 다시금 마음을 돌려서 일지 형태로 글을 작성한다. 검색을 통해 들어오신 분들에게는 다소 죄송하나 블로그의 글 처럼 나의 발자취이다. 내가 어떻게 생각하고 어떻게 검색하고 어떻게 진행했는지를 나타내는 글이라는 것을 다시금 상기시켜주길 바란다.
플러터의 기본적인 것들을 모두 찍먹해봤다. 궁금한게 많지만 처음부터 그 모든 것들을 다 알고 지나갈 수 없지 않은가? 나는 클래스 정의 문서를 살펴보고 개발을 진행하는 사람이 아니었다. (난 설명서를 보지 않지.) 그러다보니 뭘 해볼까? 라는 생각을 계속 가지고 있었다. 그리고 곰곰히 생각하던 차에 '할 일 목록'을 만들어볼까? 라는 생각을 해봤다. 그리고 실행에 옮기는데 아직도 못했다! 단지 갑자기 궁금한게 생겼을 뿐이다.
다른 사람이 만든 위젯을 어떻게 통합테스트 하지?
할 일 목록을 만들면 보통 '언제까지 해야 한다', '언제 하기로 했다' 정도로 일정을 작성하곤 한다. 이를 통해 오늘 해야 할 일, 오늘까지 해야 할 일 정도로 나뉜다. 그리고 자연스럽게 떠오르는 위젯은 DatePicker 였다. 그렇다면 이건 어떻게 테스트를 해야 할까?
AI를 이용해 DatePicker 를 테스트 코드를 작성해보자.
AI를 활용하여 DatePicker 를 테스트 하고 싶었다. 그래서 ChatGPT와 Flutter 코파일럿을 이용해 답을 요청했다.
integration test 코드를 구현해줘. 날짜를 선택하는 위젯을 누른 후 오늘 날짜에서 한달전 날짜를 선택하여 검증하는 테스트 코드를 작성해줘.
정말 놀랍게도 실행 가능한 코드를 제공해주었다. 무엇보다 기본적인 부분들을 새로 작성하지 않아도 되니 너무 편하고 좋았는데.. 막상 실행해보니 동작을 안했다.
import 'package:flutter/material.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("Select date one month before today and verify", (WidgetTester tester) async { app.main(); await tester.pumpAndSettle(); // 날짜 선택 버튼을 찾아 탭합니다. final Finder dateButton = find.byType(ElevatedButton); await tester.tap(dateButton); await tester.pumpAndSettle(); // 현재 날짜에서 한 달 전을 계산합니다. DateTime oneMonthBefore = DateTime.now().subtract(Duration(days: 30)); // 날짜 선택기에서 한 달 전 날짜를 선택합니다. await tester.tap(find.text('${oneMonthBefore.day}')); await tester.pumpAndSettle(); // 확인 버튼을 찾아 탭합니다. final Finder okButton = find.text('OK'); await tester.tap(okButton); await tester.pumpAndSettle(); // 선택된 날짜를 검증합니다. expect(find.text("${oneMonthBefore.toLocal()}".split(' ')[0]), findsOneWidget); }); }
오늘로부터 30일 전 날짜를 가져오는 부분은 잘 만들어줬으나 DatePicker 에서 한달 전으로 이동하는 부분의 코드가 사라져있었다.
그리고 위젯도 함께 작성해줬는데 선택된 결과물을 얻어오는 위젯의 정의가 아래 코드처럼 제공되어 결과를 체크하는 부분에서 오류가 발생하고 있었다.
Text( "Selected Date: ${selectedDate.toLocal()}".split(' ')[0], style: TextStyle(fontSize: 55, fontWeight: FontWeight.bold), ),
기대한 결과값은 "YYYY-MM-dd" 의 형태인데 화면상으로는 "Selected"만 계속해서 표현되고 있었다.
이러한 부분에서 AI에 대해 아쉬운 점이 있었다는 것으로 충분했다.
그렇다면 어떻게 테스트를 잘 돌게 만들 수 있을까?
DatePicker 는 버전별로, 옵션별로 디자인이 상이하다. 그래서 현재 화면에서 보여지는 형태를 체크해야 했다. datepicker_widget.dart 파일로 접근하여 build() 메소드를 확인했다.
CalendarDatePicker calendarDatePicker() { return CalendarDatePicker( key: _calendarPickerKey, initialDate: _selectedDate.value, firstDate: widget.firstDate, lastDate: widget.lastDate, currentDate: widget.currentDate, onDateChanged: _handleDateChanged, selectableDayPredicate: widget.selectableDayPredicate, initialCalendarMode: widget.initialCalendarMode, ); }
여러개의 build 메소드가 존재하는데 몇번 살펴보니 CalendarDatePicker 라는게 존재함을 발견했다. calendar_date_picker.dart 파일로 접근해서 확인해봤다. 그리고 MonthPicker 라는 클래스가 존재함을 발견했다.
@override Widget build(BuildContext context) { final Color controlColor = Theme.of(context).colorScheme.onSurface.withOpacity(0.60); return Semantics( child: Column( children: <Widget>[ Container( padding: const EdgeInsetsDirectional.only(start: 16, end: 4), height: _subHeaderHeight, child: Row( children: <Widget>[ const Spacer(), IconButton( icon: const Icon(Icons.chevron_left), color: controlColor, tooltip: _isDisplayingFirstMonth ? null : _localizations.previousMonthTooltip, onPressed: _isDisplayingFirstMonth ? null : _handlePreviousMonth, ), IconButton( icon: const Icon(Icons.chevron_right), color: controlColor, tooltip: _isDisplayingLastMonth ? null : _localizations.nextMonthTooltip, onPressed: _isDisplayingLastMonth ? null : _handleNextMonth, ), ],
IconButton 이 있고 이를 통해 달을 오가는 것을 확인했다. 자 그러면 이 달을 이동하는 로직을 추가해주면 되겠구나 싶었고 ChatGPT에 해당 아이콘이 존재하는 아이콘 버튼을 찾는 방법에 대해 물어봤다.
특정 Icon 을 가지고 있는 IconButton을 테스트 코드의 find로 찾으려면 어떻게 해야하지?
Flutter Copilot
Flutter의 통합 테스트에서 특정 Icon을 가진 IconButton을 찾기 위해, find.byWidgetPredicate 함수를 사용할 수 있습니다. 이 함수를 사용하면, 특정 조건을 만족하는 위젯을 찾을 수 있습니다. IconButton 내부에 있는 Icon 위젯의 icon 프로퍼티를 검사하여 해당 아이콘을 가진 버튼을 찾을 수 있습니다.
다음은 Icons.add 아이콘을 가진 IconButton을 찾는 예제 코드입니다:이렇게 답변을 해주며 예제를 제공해주었다.
Finder backButton = find.byWidgetPredicate( (Widget widget) => widget is IconButton && widget.icon is Icon && (widget.icon as Icon).icon == Icons.chevron_left, ); await tester.tap(backButton); await tester.pumpAndSettle();
그래서 해당 소스를 기반으로 원하는 동작을 위한 Icon을 추가하여 돌려주었고 테스트를 통과 시킬 수 있었다.
결론
AI 를 활용해 코드를 짜는 방안에 대해서 고민해봤고 실제 적용해보니 크게 생산성 향상이나 편리함을 느낄 수는 없었지만 적어도 보일러플레이트 코드를 생성하지 않음은 분명 좋았다. 그리고 매번 검색해서 찾는 방법보다 코파일럿을 이용한 개발을 진행하면서 평소 막혔던 부분을 막힘없이 술술 풀어나가는 느낌이 좋았다. 자주 써보자!
반응형'Archiving > Flutter' 카테고리의 다른 글
Figma 같은 확대 / 축소 / 이동 구현이 궁금했다 (0) 2024.10.05 [마테리얼위젯] 날짜 선택 (DatePicker) (0) 2024.02.07 3화. 플러터 통합테스트 찍먹 (0) 2024.01.26 2화. 위젯도 테스트 코드부터 (2) 2024.01.25 1화. 항상 시작합니다. TDD (2) 2024.01.23