fetchAlbum() 함수는 다음 두 가지 중 하나를 수행합니다.
http 호출이 성공하면 앨범을 반환합니다.
http 호출이 실패하면 예외를 throw합니다.
따라서 이 두 가지 조건을 테스트하고 싶습니다.
MockClient 클래스를 사용하여 성공 테스트에 대한 "Ok" 응답과 실패한 테스트에 대한 오류 응답을 반환합니다.
Mockito에서 제공하는 when() 함수를 사용하여 이러한 조건을 테스트합니다.
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:mocking/main.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'fetch_album_test.mocks.dart';
// Mockito 패키지를 사용하여 MockClient를 생성합니다.
// 각 테스트에서 이 클래스의 새 인스턴스를 생성합니다.
([http.Client])
void main() {
group('fetchAlbum', () {
test('http 호출이 성공적으로 완료되면 Album을 반환합니다.', () async {
final client = MockClient();
// 제공된 http.Client가 호출될 때 Mockito를 사용하여 성공적인 응답을 반환합니다.
when(client
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1')))
.thenAnswer((_) async =>
http.Response('{"userId": 1, "id": 2, "title": "mock"}', 200));
expect(await fetchAlbum(client), isA<Album>());
});
test('http 호출이 에러와 함께 완료되면 예외를 발생시킵니다.', () {
final client = MockClient();
// 제공된 http.Client가 호출될 때 Mockito를 사용하여 실패한 응답을 반환합니다.
when(client
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1')))
.thenAnswer((_) async => http.Response('Not Found', 404));
expect(fetchAlbum(client), throwsException);
});
});
}
class PixabayApi {
final http.Client client;
PixabayApi(this.client);
static const baseUrl = 'https://pixabay.com/api/';
static const key = '10711147-dc41758b93b263957026bdadb';
Future<Result<Iterable>> fetch(String query) async {
try {
final response = await client
.get(Uri.parse('$baseUrl?key=$key&q=$query&image_type=photo'));
Map<String, dynamic> jsonResponse = jsonDecode(response.body);
Iterable hits = jsonResponse['hits'];
return Result.success(hits);
} catch (e) {
return const Result.error('네트워크 에러');
}
}
}
PixabayApi 클래스는 API 요청을 처리하는 역할을 합니다.
테스트에서는 client.get 메서드의 결과를 JSON으로 파싱하고, 이를 Photo 객체 리스트로 변환합니다.
import 'pixabay_api_test.mocks.dart';
([http.Client])
void main() {
test('Pixabay 데이터를 잘 가져와야 한다', () async {
final client = MockClient();
final api = PhotoApiRepositoryImpl(PixabayApi(client));
when(client.get(Uri.parse(
'${PixabayApi.baseUrl}?key=${PixabayApi.key}&q=iphone&image_type=photo')))
.thenAnswer((_) async => http.Response(fakeJsonBody, 200));
final Result<List<Photo>> result = await api.fetch('iphone');
expect((result as Success<List<Photo>>).data.first.id, 410311);
verify(client.get(Uri.parse(
'${PixabayApi.baseUrl}?key=${PixabayApi.key}&q=iphone&image_type=photo')));
});
}
String fakeJsonBody = """
{"total":1320,"totalHits":500,"hits":[{"id":410311,"pageURL":"https://pixabay.com/photos/iphone-hand-screen-smartphone-apps-410311/","type":"photo","tags":"iphone, hand, screen","previewURL":"https://cdn.pixabay.com/photo/2014/08/05/10/27/iphone-410311_150.jpg","previewWidth":150,"previewHeight":99,"webformatURL":"https://pixabay.com/get/ga40944969ab1ca0cb5e5e2a753382c5ef38aa9b1bdf195f44a6e8c7def03f5b2ce08c74211f5bd254565642907f5e7b5_640.jpg","webformatWidth":640,"webformatHeight":426,"largeImageURL":"https://pixabay.com/get/gac97151d90f6f74f39ba9a6013d97a3e0c8b3b2673356bef20a65b9a253d439913d8d3566a6e8485773b9aea90170c38a538a3582b0a2af3e51efe53ebc8885b_1280.jpg","imageWidth":1920,"imageHeight":1280,"imageSize":416413,"views":441374,"downloads":213676,"collections":2913,"likes":573,"comments":146,"user_id":264599,"user":"JESHOOTS-com","userImageURL":"https://cdn.pixabay.com/user/2014/06/08/15-27-10-248_250x250.jpg"},{...} 생략
]
Pixabay API가 반환할 것 같은 응답 형식을 그대로 유지하면서 필요한 데이터만 포함합니다. 예: id, tags, previewURL 등.
String fakeJsonBody = """
{"total":1320,"totalHits":500,"hits":[{"id":410311, ...}]
""";
MockClient는 http 패키지에서 제공하는 클라이언트를 모킹하기 위한 도구입니다.
실제 HTTP 요청을 보내지 않고, fakeJsonBody를 반환하도록 설정합니다.
test('pixabay 이미지 검색 테스트', () async {
final client = MockClient();
when(client.get(any))는 모든 GET 요청에 대해 응답을 모킹합니다.
thenAnswer를 사용해 JSON 응답(fakeJsonBody)과 HTTP 상태 코드(200)를 반환하도록 설정합니다.
when(client.get(any)).thenAnswer(
(_) async => http.Response(fakeJsonBody, 200),
);
PixabayApi 클래스의 fetchImages 메서드를 호출합니다.
fetchImages는 API를 통해 "iphone" 키워드로 이미지를 검색하는 메서드입니다.
final result = await PixabayApi(client).fetchImages('iphone');
호출 결과가 Success 타입이어야 하며, 첫 번째 이미지의 id가 410311인지 확인합니다.
이는 fakeJsonBody에 정의된 데이터를 기반으로 올바르게 처리되었는지 검증하는 과정입니다.
expect((result as Success<List<Photo>>).data.first.id, 410311);
실제 호출된 URL이 예상한 것과 일치하는지 확인합니다.
verify(client.get(Uri.parse(
'${PixabayApi.baseUrl}?key=${PixabayApi.key}&q=iphone&image_type=photo')));
이 테스트는 Pixabay API의 기능을 가상으로 흉내 내어 정상적으로 동작하는지 확인하기 위해 작성되었습니다.
특히 네트워크 호출 없이도 API 로직을 검증할 수 있도록 MockClient와 fakeJsonBody를 활용한 점이 특징입니다.
import 'package:http/testing.dart';
void main() {
test('Pixabay 이미지를 잘 가져와야 한다', () async {
final mockClient = MockClient((request) async{
if (request.url.toString() ==
'${PixabayApi.baseUrl}?key=${PixabayApi.key}&q=iphone&image_type=photo') {
return http.Response(fakeJsonBody, 200);
}
return http.Response('Not Found', 404);
});
final api = PixabayApi(client: mockClient));
//실행
List<Photo> photos = await api.fetch('iphone');
//검증
expect(photos[0].previewUrl,
'https://cdn.pixabay.com/photo/2014/08/05/10/27/iphone-410311_150.jpg');
expect(photos.length, 20);
});
}
const fakeDate = """
{"total":8794,"totalHits":500,"hits":[{"id":634572,"pageURL":"https://pixabay.com/photos/iphone-6-apple-ios-634572/","type":"photo","tags":"iphone 6, apple, ios","previewURL":"https://cdn.pixabay.com/photo/2014/08/05/10/27/iphone-410311_150.jpg","previewWidth":150,"previewHeight":99,"webformatURL":"https://pixabay.com/get/52e1d3434c51ae14f6da8c7dda79367b113adde04e507441722a7cd6904bc658_640.jpg","webformat}
""";
test('Pixabay 이미지를 잘 가져와야 한다', () async {
final mockClient = MockClient((request) async {
MockClient는 API 호출을 가상으로 흉내 내는 역할을 합니다.
이를 통해 실제 네트워크 호출 없이 미리 정의된 응답을 반환하도록 설정할 수 있습니다.
request는 http.Request 객체를 의미하며, 요청에 따라 다른 응답을 반환할 수 있도록 설정합니다.
if (request.url.toString() ==
'${PixabayApi.baseUrl}?key=${PixabayApi.key}&q=iphone&image_type=photo') {
return http.Response(fakeJsonBody, 200);
}
return http.Response('Not Found', 404);
요청 URL이 Pixabay API의 검색 URL과 정확히 일치할 경우:
미리 정의된 JSON 데이터(fakeJsonBody)를 HTTP 응답으로 반환합니다.
상태 코드는 200(정상 응답)을 반환합니다.
요청 URL이 일치하지 않을 경우:
'Not Found' 메시지와 상태 코드 404(페이지 없음)을 반환합니다.
final api = PixabayApi(client: mockClient));
PixabayApi 클래스의 인스턴스를 생성하면서, client로 mockClient를 전달합니다.
이를 통해 PixabayApi가 실제 네트워크 호출 대신 mockClient를 통해 요청과 응답을 처리하도록 설정합니다.
List<Photo> photos = await api.fetch('iphone');
PixabayApi 클래스의 fetch() 메서드를 호출하여 키워드 "iphone"에 해당하는 이미지 목록을 요청합니다.
요청 결과는 List 형태로 반환됩니다.
이 테스트에서는 mockClient에 의해 미리 정의된 fakeJsonBody가 반환되므로 실제 네트워크 호출은 발생하지 않습니다.
expect(photos[0].previewUrl,
'https://cdn.pixabay.com/photo/2014/08/05/10/27/iphone-410311_150.jpg');
expect(photos.length, 20);
expect()는 테스트에서 예상되는 결과를 검증하는 함수입니다.
첫 번째 expect : 첫 번째 이미지의 previewUrl 속성이 예상된 URL과 일치하는지 확인합니다.
두 번째 expect : 반환된 이미지 리스트의 길이가 20인지 확인합니다.