Flutter
[Flutter] Mocktail 패키지로 api 메서드 테스트하기
mjjayce
2025. 5. 13. 20:11
기존에 Mocktail 패키지를 사용해 가짜 데이터로 메서드를 테스트하는 방식은 알고 있었지만, api를 사용하는 메서드의 경우 서버 통신을 어떻게 대체해야 하나 하는 고민이 있었다.
결론적으로 api통신 메서드의 경우에도 방법은 같다. 서버와 통신해서 실제 데이터를 가져오는 부분을 생략하고, 가짜 데이터를 넣어 해당 데이터를 잘 처리할 수 있는지 테스트해 준다.
테스트할 코드.
가짜 데이터 생성을 위해 dio를 외부 생성자로 받아 주는 클래스 구조를 만들었다.
fetchNowPlayingMovies 메서드는 tmdb에게 현재 상영중인 영화 데이터를 요청하고, 그 데이터로 List<MovieResponseDto>?를 반환한다.
이 메서드를 테스트할 때는,
get 요청이 발생하면 가짜 데이터를 Response.data로 취급하도록 하는 코드
를 작성해 메서드가 데이터를 받아온 이후 작업을 잘 처리하는지 확인하면 된다.
테스트 코드
import 'package:dio/dio.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:movie_info_app/data/data_source/movie_api_data_source_impl.dart';
class MockDio extends Mock implements Dio {}
void main() {
// 테스트 세팅
// setUp함수는 테스트 실행 전에 자동으로 실행됨
// mockDio를 초기화하고, MovieApiDataSourceImpl클래스의 외부 생성자로 이용해 movieApi객체를 생성함
MockDio? mockDio;
MovieApiDataSourceImpl? movieApi;
setUp(() {
mockDio = MockDio();
movieApi = MovieApiDataSourceImpl(dio: mockDio!);
});
// fetchNowPlayingMovies test
test(
'MovieApiDataSourceImpl : fetchNowPlayingMovies return data test',
() async {
// when / thenAnswer 문
// when : mockDio!.get(any()) 어느 get 요청이든 발생하면
// thenAnswer : 이 Map데이터를 비동기적으로 반환해라
// 즉, 실제 서버 통신을 하는 대신 가짜 data를 주는 것으로 속임
when(() {
return mockDio!.get(any());
}).thenAnswer(
(_) async => Response(
data: {
'results': [
{
"adult": false,
"backdrop_path": "/cJvUJEEQ86LSjl4gFLkYpdCJC96.jpg",
"genre_ids": [10752, 28],
"id": 1241436,
"original_language": "en",
"original_title": "Warfare",
"overview":
"A platoon of Navy SEALs embarks on a dangerous mission in Ramadi, Iraq, with the chaos and brotherhood of war retold through their memories of the event.",
"popularity": 538.9681,
"poster_path": "/j8tqBXwH2PxBPzbtO19BTF9Ukbf.jpg",
"release_date": "2025-04-09",
"title": "Warfare",
"video": false,
"vote_average": 7.135,
"vote_count": 233,
},
],
},
// 실제 실행시에는 request url을 처리할 때 자동으로 채워지는 객체
// 필수 옵션이므로 테스트 때에도 채워줘야 하지만, 테스트 때는 실제 서버 통신이 이뤄지지 않으므로 빈 path 넣음
requestOptions: RequestOptions(path: ''),
),
);
// 실제 메서드 호출 + 검증
// 진짜처럼 fetchNowPlayingMovies()를 호출함
// fetchNowPlayingMovies 내부에서는 get요청이 발생하는데, 이 때 when문 조건에 걸림
// 실제 서버 통신을 하는 대신 테스트용 가짜 data를 읽게 됨
final results = await movieApi!.fetchNowPlayingMovies();
expect(results![0].adult, false);
expect(results[0].backdropPath, "/cJvUJEEQ86LSjl4gFLkYpdCJC96.jpg");
expect(results[0].genreIds, [10752, 28]);
},
);
}