An introduction to unit testing
๐ ๋จ์ ํ ์คํธ ์๋๋ฆฌ์ค
- mickito & test ์์กด์ฑ ์ถ๊ฐ
- ํ ์คํธํ ํจ์ ์์ฑํ๊ธฐ
- http.Client Mock ๊ฐ์ฒด์ ํจ๊ป ํ ์คํธ ํ์ผ ์์ฑํ๊ธฐ
- ๊ฐ ์กฐ๊ฑด๋ง๋ค ํ ์คํธ ์์ฑํ๊ธฐ
- ํ ์คํธ ์ํํ๊ธฐ
1. ๐จ๐ปโ๐ป mockito์์กด์ฑ ์ถ๊ฐํ๊ธฐ
mockito ์์กด์ฑ์ ์ถ๊ฐํ๊ธฐ ์ํด pubspec.yaml
ํ์ผ์ dev_dependencies
์์ญ์ flutter_test ์์กด์ฑ๊ณผ ํจ๊ป ์ถ๊ฐํ๋ค.
๐ http ํจํค์ง๋ ์ฌ์ฉํด์ผ ํ๊ธฐ ๋๋ฌธ์ dependencies์์ญ์ ์ถ๊ฐํ๋ค.
dependencies:
http: <newest_version>
dev_dependencies:
test: <newest_version>
mockito: <newest_version>
Tip : Flutter version์ ๋ฐ๋ผ test์ ๋ฒ์ ์ด ๋ฌ๋ผ์ง ์ ์์.
์ ๋ ํ์ฌ 1.17.3์ Flutter stable version์ ์ฌ์ฉํ๊ณ ์๊ณ , test๋ 1.14.4๋ฒ์ ์ด๋ค.
http: ^0.12.2
...
test: ^1.14.4
mockito: ^4.1.1
2. ๐จ๐ปโ๐ป ํ ์คํธํ ํจ์ ์์ฑํ๊ธฐ
๋ณธ ์์ ์์๋ ์ธํฐ๋ท์์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ์์ ์ fetchPost
ํจ์๋ฅผ ๋จ์ ํ
์คํธํ๋ค. ์ด ํ
์คํธ๋ฅผ ์ํด์ ๋๊ฐ์ง ๋ณ๊ฒฝ์ด ํ์ํ๋ค.
- ํจ์์
http.Client
๋ฅผ ์ ๊ณตํด์ผํ๋ค. - mock ๊ฐ์ฒด๋ก ๋ง๋ค๊ธฐ ์ด๋ ค์ด static
http.get()
method๊ฐ ์๋, ์ ๊ณต๋client
๋ฅผ ์ฌ์ฉํ์ฌ ์๋ฒ๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์จ๋ค.
๐ขPost๋ผ๋ class๋ฅผ ๋ฏธ๋ฆฌ ์ ์ํด๋์ด์ผ ํ๋ค. ์ธํฐ๋ท์์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ์ ๋ณด๋ฉด ๋์ด.
Future<Post> fetchPost(http.Client client) async {
final response =
await client.get('https://jsonplaceholder.typicode.com/posts/1');
if (response.statusCode == 200) {
// ๋ง์ฝ ์๋ฒ๋ก์ ์์ฒญ์ด ์ฑ๊ณตํ๋ค๋ฉด, JSON์ผ๋ก ํ์ฑํฉ๋๋ค.
return Post.fromJson(json.decode(response.body));
} else {
// ๋ง์ฝ ์์ฒญ์ด ์คํจํ๊ฒ ๋๋ฉด, ์๋ฌ๋ฅผ ๋์ง๋๋ค.
throw Exception('Failed to load post');
}
}
โ
https://jsonplaceholder.typicode.com/posts/1 ์ ๊ฒฐ๊ณผ๊ฐ :
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
3. ๐จ๐ปโ๐ป http.Client Mock ๊ฐ์ฒด์ ํจ๊ป ํ ์คํธ ํ์ผ ์์ฑํ๊ธฐ
์ด์ MockClient
ํด๋์ค์ ํจ๊ป ํ
์คํธ ํ์ผ์ ๋ง๋ค ์ฐจ๋ก์ด๋ค. ๋จ์ํ
์คํธ ์๊ฐ ์์ ๋ฅผ ๋ฐ๋ผ ์ต์์ test
ํด๋ ์์ fetch_post_test.dart
ํ์ผ์ ์์ฑํ๋ค.
MockClient
ํด๋์ค์์๋ http.Client
ํด๋์ค๋ฅผ ๊ตฌํํ ๊ฒ์ด๋ค. ์ด๋ฅผ ํตํด MockClient
๋ฅผ fetchPost
ํจ์์ ์ ๋ฌํ ์ ์๊ฒ ๋๋ฉฐ, ๊ฐ ํ
์คํธ๋ง๋ค ๋ค๋ฅธ http ์๋ต์ ๋ฐํํ ์ ์๊ฒ ํด์ค๋ค.
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:mockito/mockito.dart';
// Mockito ํจํค์ง์์ ์ ๊ณต๋๋ Mock ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ MockClient๋ฅผ ์์ฑํฉ๋๋ค.
// ๊ฐ ํ
์คํธ ๋ง๋ค ์ด ํด๋์ค์ ์๋ก์ด ์ธ์คํด์ค๋ฅผ ์์ฑํ์ธ์.
class MockClient extends Mock implements http.Client {}
main() {
// ํ
์คํธ ์ฝ๋๋ ์ฌ๊ธฐ์ ์์นํฉ๋๋ค.
}
4. ๊ฐ ์กฐ๊ฑด๋ง๋ค ํ ์คํธ ์์ฑํ๊ธฐ
์์์ ์์ฑํ fetchPost()
ํจ์๋ ๋ ๊ฐ์ง ์ผ ์ค ํ๋๋ฅผ ์ํํ๊ฒ ๋๋ค.
- http ์์ฒญ์ด ์ฑ๊ณตํ๋ฉด
Post
๋ฅผ ๋ฐํํ๋ค. - http ์์ฒญ์ด ์คํจํ๋ฉด
Exception
์ ๋์ง๋ค.
๋ฐ๋ผ์ ๋๊ฐ์ง ๊ฒฝ์ฐ์ ๋ฐ๋ผ ํ
์คํธ ์ฝ๋๋ฅผ ์์ฑํด์ผ ํ๋ค. MockClient
ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ๊ณต ์ผ์ด์ค๋ฅผ ์ํด OK
์๋ต์ ๋ฐํํ ์๋ ์๊ณ , ์คํจ ์ผ์ด์ค๋ฅผ ์ํด Error
์๋ต ๋ฐํ์ ์ ๋ํ ์ ์๋ค. ์ด๋ฌํ ์กฐ๊ฑด์ Mockito
๊ฐ ์ ๊ณตํ๋ when()
ํจ์๋ฅผ ์ฌ์ฉํด์ ํ
์คํธ ํ ์ ์๋ค.
main() {
group('fetchPost', () {
test('returns a Post if the http call completes successfully', () async {
final client = MockClient();
// ์ ๊ณต๋ http.Client๋ฅผ ํธ์ถํ์ ๋, ์ฑ๊ณต์ ์ธ ์๋ต์ ๋ฐํํ๊ธฐ ์ํด
// Mockito๋ฅผ ์ฌ์ฉํฉ๋๋ค.
when(client.get('https://jsonplaceholder.typicode.com/posts/1'))
.thenAnswer((_) async => http.Response('{"title": "Test"}', 200));
expect(await fetchPost(client), isInstanceOf<Post>());
});
test('throws an exception if the http call completes with an error', () {
final client = MockClient();
// ์ ๊ณต๋ http.Client๋ฅผ ํธ์ถํ์ ๋, ์คํจ ์๋ต์ ๋ฐํํ๊ธฐ ์ํด
// Mockito๋ฅผ ์ฌ์ฉํฉ๋๋ค.
when(client.get('https://jsonplaceholder.typicode.com/posts/1'))
.thenAnswer((_) async => http.Response('Not Found', 404));
expect(fetchPost(client), throwsException);
});
});
}
5. ํ ์คํธ ์ํํ๊ธฐ
IDE๋ฅผ ์ฌ์ฉํ๋ค๋ฉด, run ๋ฒํผ์ ์ด์ฉํด์ ํ
์คํธ ๊ฐ๋ฅํ๊ณ
editor๋ฅผ ์ฌ์ฉํ๋ค๋ฉด command line์์ ๋ค์ ๋ช
๋ น์ด๋ฅผ ์
๋ ฅํ๋ฉด ๊ฐ๋ฅํ๋ค.
flutter test
ํ์ผ๋ช
ex) $flutter test test/unit_test/http_test_fetchPost.dart
'App > Flutter' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Flutter] Test Code (0) | 2020.07.26 |
---|---|
[Flutter] Test ์ข ๋ฅ (0) | 2020.07.15 |
[Flutter Codelab] Adding AdMob ads (0) | 2020.07.02 |
[Flutter Codelab] Adding Google Maps (0) | 2020.06.30 |
[Flutter] 3. Wrap (0) | 2020.06.22 |
๋๊ธ