Testing Flutter Apps | Flutter
์ด๋ฒ ๊ธ์์๋ Flutter์์ ์ดํ๋ฆฌ์ผ์ด์ ์ ํ ์คํ ํ๋ ๋ฐฉ๋ฒ ๋ฐ ์ ํ์ ๋ํด์ ์ดํด๋ณด๋๋ก ํ๊ฒ ๋ค.
Flutter๋ ๋ค๋ฅธ ํ๋ ์์ํฌ๋ ์ธ์ด์ฒ๋ผ ๊ฐ๋ฐํ ๊ธฐ๋ฅ์ ํ ์คํธํ๊ฑฐ๋, ๋ง๋ค๊ณ ์ ํ๋ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ ์ ํ ์คํธ๋ฅผ ํ ์ ์๋๋ก ์ง์ํด์ฃผ๊ณ ์๋ค.
ํ ์คํธ๋ ํ์๊ฐ ์๋ ์ ํ์ ์์ญ์ด๋ค ๋ณด๋, ๋ชจ๋ ๊ธฐ๋ฅ์ ๋ํด ํ ์คํธ๋ฅผ ํ๋ ๊ฒฝ์ฐ๋ ์๊ณ ์ผ๋ถ ๊ธฐ๋ฅ๋ง ํ๋ ๊ฒฝ์ฐ๋ ์๊ณ ์ฌ์ง์ด๋ ์์ ์ฝ๋ ํ ์คํธ๋ฅผ ์งํํ์ง ์๋ ์๋น์ค๋ ์๋ค.
์ด์ฒ๋ผ ์ ํ์ ์์ญ์ด๋ค ๋ณด๋ ์๊ฐ์ ํฌ์ํ๋ฉด์ ๊น์ง ํ ์คํธ ์ผ์ด์ค๋ฅผ ์๊ฐํ๊ณ ์์ฑํ๋ ๊ฒ์ด ๋ถํ์ํ๋ค๊ณ ๋๋ผ๋ ๊ฐ๋ฐ์๋ ์๊ณ , ์ถํ์ ์๋น์ค๊ฐ ํ๋๋จ์ ๋ฐ๋ผ ์์ ๋ ์์ญ์ ์ฝ๋๊ฐ ์ ์์ ์ผ๋ก ์๋ํ๋ ์ง๋ฅผ ๋ฏธ๋ฆฌ ํ ์คํธ ์ฝ๋๋ก ์์ฑํ์ฌ ๋์ค์ ๋ฐ์ํ ์๋ ์๋ ์๊ฐ์ ๋จ์ถํ๋ ๊ฒ์ด ํ์ํ๋ค๊ณ ์๊ฐํ๋ ๊ฐ๋ฐ์๋ ์๋ค.
๊ฒฝํํ๊ฑฐ๋ ๋น์ฅ์ ์ฌ์ฉํ์ง ์๋๋ผ๋ Flutter์์๋ ์ด๋ป๊ฒ ์ฝ๋๋ฅผ ํ ์คํธํ๊ณ UI๋ฅผ ํ ์คํธํ๋์ง ์์๋ฌ์ ๋์ ๊ฒ์ ์๊ธฐ ๋๋ฌธ์ ๊ฐ๋ณ๊ฒ ์ฝ์ด๋ณด์๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค.
์ ํ๋ฆฌ์ผ์ด์ ํ ์คํ ์ ์ ํด์ผํ๋ ๊ฑธ๊น ?
์์ฒด์ ์ผ๋ก QA๋ฅผ ์งํํ๋๋ฐ, ์ ๋ณ๋๋ก ์ ํ๋ฆฌ์ผ์ด์ ํ ์คํ ๋ ์งํ ํด์ผ๋ง ํ๋ ๊ฑด์ง๋ ๋น์ฐํ ์ด์ ์ด๊ฒ ์ง๋ง ์ฑ์ ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋ ๋๋ง๋ค ์ ์ฒด ์์ญ์ ์ฝ์ดํ ๊ธฐ๋ฅ๋ค์ ๋ํด์๊น์ง QA๋ฅผ ์งํํ๋ ๊ฒ์ ๋ง์ ์๊ฐ์ด ์์๋๊ธฐ ๋๋ฌธ์, ๊ฐ๋ฐ๋จ์์ ์ฌ์ ์ ์ฝ๋์ ๋ฌธ์ ๊ฐ ์๋์ง, ์ถ๊ฐ๋ ์ฝ๋๋ก ์ธํ์ฌ ๊ธฐ์กด์ ๊ธฐ๋ฅ์๋ ๋ฌธ์ ๊ฐ ์๋์ง๋ฅผ ์๋์ผ๋ก ํ ์คํ ์ ํ๋ ๊ฒ์ด๋ค.
์ผ๋ฐ์ ์ผ๋ก ์ฝ๋ ํ ์คํ ์ ์งํํ๋ ๋ชฉ์ ์ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์๊ฒ ์ง๋ง, ๋ฒ๊ทธ ๋ฐ ์ฝ๋์ ๊ฒฐํจ์ ์์ ๊ณ ๊ฐ๋ฐ์๊ฐ ์๋ํ ๋๋ก ๊ธฐ๋ฅ์ด ์ํ์ ์ํค๋ฉฐ ๋ค์ํ ์๋๋ฆฌ์ค์์ ์๋น์ค๊ฐ ์์ ์ ์ผ๋ก ๊ตฌ๋์ด ๋๋์ง๋ฅผ ํ์ธํ๊ฒ ๋๋ค. ๋ํ ์ด๊ธฐ์๋ ํ ์คํธ ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ฉด์ ๊ฐ๋ฐ ์๋๊ฐ ๋ฆ์ด์ง ์ ์์ง๋ง ์ถํ์ ์๋ํ๋ ํ ์คํธ๋ฅผ ํตํด ๋ฐ๋ณต์ ์ธ ์์์ ํ ์คํธ๋ฅผ ์ค์ผ ์ ์์ด ์๋๋ฅผ ๋ํ ์ ์์ผ๋ฉฐ, ์์ฑ๋ ํ ์คํธ ์ฝ๋๊ฐ ๊ธฐ๋ฅ์ ๋ฌธ์ํํ๋๋ฐ ๋์์ด ๋๊ธฐ ๋๋ฌธ์ด๋ผ๊ณ ์๊ฐํ๋ค.
์ฆ, ๋จ์ํ ์ด์๋ฅผ ์ฐพ์๋ด๋ ๊ฒ์ด ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ๋ฐ์ ์ธ ํ์ง ๋ฐ ๊ฒ์ฆ์ ํ๋ ์ ์ฐจ๋ผ๊ณ ๋ณผ ์ ์๋ค.
ํ ์คํธ๋ฅผ ์ํด์๋ ํจํค์ง ์ถ๊ฐ๊ฐ ํ์ํ๋ฐ, ํด๋น ํจํค์ง๋ ํ๋ก์ ํธ ์์ฑ์ ์๋ ์ถ๊ฐ๋ ํจํค์ง๋ผ ์๋ค๋ฉด ์ถ๊ฐํ๋ฉด ๋๋ค.
flutter_test ํจํค์ง๋ ๊ฐ๋ฐ์์๋ง ์ฌ์ฉํ๋ฉด ๋๊ธฐ์ dev_dependencies์ ์ถ๊ฐํด์ฃผ๋ฉด ๋๋ค.
dev_dependencies:
flutter_test:
sdk: flutter
ํ ์คํธ๋ฅผ ์ํด์ ์ฌ์ฉํ๋ ํ ์คํธ ๊ด๋ จ ํ์ผ๋ค์ ๋ฐ๋์ test ํด๋์์ ๋ฃ์ด์ผ๋ง ์ ์์ ์ผ๋ก ๋์ํ๋ ์๋ค๋ฉด test ํด๋๋ฅผ ์์ฑํด ์ฃผ์ด์ผ ํ๋ค.
Flutter์์๋ Unit, Widet(UI), Intergration ์ด๋ ๊ฒ 3๊ฐ์ง ์ ํ์ ํ ์คํ ์ ์งํํ ์ ์๋๋ก ์ง์ํ๊ณ ์๋ค.
์ด์ ๊ฐ๊ฐ์ ํ ์คํ ๋ฐฉ๋ฒ์ ๋ํด์ ๋ค๋ค๋ณด๋๋ก ํ์.
์ฒซ ๋ฒ์งธ๋ก ์ดํด๋ณผ ํ ์คํ ๋ฐฉ๋ฒ์ Unit Test์ด๋ค.
Unit Test๋ ๋จ์ ํ ์คํธ๋ผ๊ณ ํ๋ฉฐ ๊ฐ๋ณ ํจ์, ๋ฉ์๋, ํด๋์ค ๋ฑ์ ์์ ์ฝ๋ ๋จ์๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ํ ์คํธํ์ฌ ๋ฒ๊ทธ๋ฅผ ์ฌ์ ์ ๊ฐ์ ํด ์ฝ๋์ ํ์ง๊ณผ ์์ ์ฑ์ ๋์ด๋ ํ ์คํธ ๋ฐฉ๋ฒ์ด๋ค.
๋จผ์ ๊ฐ๋จํ ์ ๋ ํ ์คํธ๋ฅผ ์งํํด๋ณด์.
test ํ์ผ์์ ์๋ ์ฝ๋๋ฅผ ์คํํด๋ณด์.
void main() {
test("Unit Testing", () => expect(1 + 1, 2));
}
์ฝ๋๋ฅผ ์คํํ ๋์๋ "Run"์ ์ฌ์ฉํ๋ฉด ๋๋ค. ํ ์คํ ๊ฒฐ๊ณผ๊ฐ ์ ์์ ์ผ๋ก ์ฑ๊ณตํ๋ฉด ์๋์ ๊ฐ์ด ์ฒดํฌ ํ์๊ฐ ํ๊ธฐ ๋๋ค.
๋ก๊ทธ์ฐฝ์์๋ ํ ์คํธ ์คํ์ ๋ํ ๊ฒฐ๊ณผ๋ฅผ ์ ์ ์๋ค.
์คํจ๊ฐ ๋๋ฉด ์ด๋ป๊ฒ ๋ ๊น ?
๊ฐ์ ๋ก ํ ์คํธ ๊ฒฐ๊ณผ๊ฐ ์คํจ๊ฐ ๋ ์ ์๋๋ก ๊ฒฐ๊ณผ ๊ฐ์ ์์ ํ์ฌ ์งํํด๋ณด์.
์คํจ๊ฐ ๋๋ฉด ์๋์ ๊ฐ์ด ์คํจ๊ฐ ๋ ๋ถ๋ถ์ด ์ด๋ค ํ ์คํธ ์ผ์ด์ค์ธ์ง๋ฅผ ํฌ์ธํธ๋ก ๋ณด์ฌ์ฃผ๋ฉด์, X ์์ด์ฝ์ด ํ๊ธฐ ๋๋ค.
์ด์ ํ ์คํธ๋ฅผ ์ด๋ป๊ฒ ํ๋์ง ๊ฐ๋จํ๊ฒ ์ดํด๋ดค์ผ๋, ๊ธฐ๋ฅ์ ๋ํด์ ์์๋ณด๋๋ก ํ์.
๋จผ์ test ํจ์์ด๋ค.
test ํจ์์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ณด๋ฉด, ํ์ ๊ฐ์ผ๋ก description, body ๊ฐ์ ์ฌ์ฉํด์ผ ํ๋ค.
void test(
Object description,
dynamic Function() body, {
String? testOn,
Timeout? timeout,
dynamic skip,
dynamic tags,
Map<String, dynamic>? onPlatform,
int? retry,
})
๊ฐ ํ๋ผ๋ฏธํฐ์ ๋ํด ๊ฐ๋จํ๊ฒ ์์๋ณด์.
description
- ํ ์คํธ์ ์ค๋ช ์ด๋ ์ด๋ฆ์ ์ง์ ํ ์ ์๊ณ , ํ ์คํธ ๊ฒฐ๊ณผ๋ก ์ถ๋ ฅ๋ ๋์ ์ฌ์ฉ
body
- ํ ์คํธํ ์ฝ๋๋ฅผ ์ถ๊ฐํ์ฌ ์ฌ์ฉ
testOn
- ํ ์คํธ๊ฐ ์คํ๋ ํ๊ฒฝ์ ์ค์ ํ์ฌ, Dart VM, ๋ธ๋ผ์ฐ์ ๋ฑ์ ํน์ ํ๊ฒฝ์์๋ง ํ ์คํธ๋ฅผ ์คํํ๋๋ก ํ ์ ์์
timeout
- ํ ์คํธ ์๋ฃ์ ๊น์ง์ ์ต๋ ์๊ฐ์ ์ง์ ํ์ฌ, ์๊ฐ ๋ด์ ํ ์คํธ๊ฐ ์๋ฃ๋์ง ๋ชปํ๋ฉด ๊ฐ์ ๋ก ์คํจ๋ก ๊ฐ์ฃผํ๋๋ก ์ฒ๋ฆฌ
skip
- ํ ์คํธ๋ฅผ ๊ฑด๋๋ธ์ง์ ๋ํ ๊ฐ์ ์ง์
tags
- ํ๊ทธ๋ฅผ ๋ฐฐ์ด ๋๋ ๋ฌธ์์ด๋ก ์ง์ ํ์ฌ ํน์ ํ๊ทธ์ ๋ํ ํ ์คํธ๋ง์ ์คํํ๊ฑฐ๋ ๊ฑด๋๋ธ ์ ์๋๋ก ํจ
onPlatform
- ํ๋ซํผ๋ณ๋ก ํ ์คํธ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ์ง์
retry
- ํ ์คํธ ์คํจ์์ ๋ํ ๋ฐ๋ณต ํ ์คํธ ํ์๋ฅผ ์ง์
test("์ด๋ค ํ
์คํธ ?", () {
// test code
});
์ด์ด์ test ํจ์์ body์ ์ค์ ๋ก ์คํํ ํ ์คํธ ์ฝ๋๋ฅผ ๋ฃ์ ๋์ ์ฌ์ฉํ๋ expect์ ๋ํด์ ์ดํด๋ณด๋๋ก ํ์.
void expect(
dynamic actual,
dynamic matcher, {
String? reason,
dynamic skip,
})
expect ํจ์๋ Flutter์์ ํ ์คํ ์ ํ๋๋ฐ ์์ด ๊ฐ์ฅ ํต์ฌ์ด ๋๋ ๊ธฐ๋ฅ์ด๋ฉฐ, ์ค์ ๊ฐ(actual)๊ณผ ์์ ๊ฐ(matcher)์ ๋น๊ตํ์ฌ ํ ์คํธ์ ์คํจ ๋ฐ ์ฑ๊ณต์ ๊ฒฐ์ ํ๋ ํจ์์ด๋ค.
์ค์ ๊ฐ์ 1๋ก ๋ฃ๊ณ , ์์ ๊ฐ์ 1๋ก ๋ฃ์ด์ฃผ๋ฉด ๋น์ฐํ ์ฑ๊ณต์ ํ ๊ฒ์ด๋ค.
expect(1, 1);
์ด๋ฒ์๋ 3+4๋ฅผ ์ค์ ๊ฐ์ ๋ฃ์ด์ฃผ๊ณ , ์์ ๊ฐ์ผ๋ก 7์ ๋ฃ์ด์ฃผ์.
expect(3 + 4, 7);
๋จ์ ๊ณ์ฐ ์ธ์๋ ์ฌ๋ฌ๊ฐ์ง ๊ฐ์ ์ฌ์ฉํ ์ ์๋ค.
expect([1, 2, 3], contains(4));
์ฌ๋ฌ ๊ธฐ๋ฅ์ ๋ํ ํ ์คํธ ์ผ์ด์ค๋ค์ ๊ทธ๋ฃน์ผ๋ก ๊ด๋ฆฌํ์ฌ ์ฌ์ฉํ ์ ์๋ค.
group ๊ธฐ๋ฅ์ ์ฌ์ฉํด ์ฌ๋ฌ ํ ์คํธ๋ค์ ๋ฌถ์ด์ ๊ด๋ จ ๋์ ํ ์คํธ๋ง ์งํํ๊ฑฐ๋ ๊ด๋ฆฌํ ์ ์๋ค.
void main() {
group("ํ
์คํธ ๊ทธ๋ฃน 1", () {
test("์ฒซ ๋ฒ์งธ ํ
์คํธ", () => null);
test("๋ ๋ฒ์งธ ํ
์คํธ", () => null);
test("์ธ ๋ฒ์งธ ํ
์คํธ", () => null);
});
group("ํ
์คํธ ๊ทธ๋ฃน 2", () {
test("์ฒซ ๋ฒ์งธ ํ
์คํธ", () => null);
test("๋ ๋ฒ์งธ ํ
์คํธ", () => null);
test("์ธ ๋ฒ์งธ ํ
์คํธ", () => null);
});
}
์ด์ ํ ์คํธ๋ฅผ ์ํ ๋ฐฉ๋ฒ์ ๋ํด์ ์์๋ดค์ผ๋, ๋ณธ๊ฒฉ์ ์ผ๋ก Unit Test๋ฅผ ํด๋ณด๋๋ก ํ์.
๋จผ์ , Counter ๊ฐ์ฒด๋ฅผ lib ์์์ ์์ฑํด์ฃผ๋๋ก ํ์.
class Counter {
int value = 0;
void increment() => value++;
void decrement() => value--;
}
Counter ๊ธฐ๋ฅ์ ๋ํ ๋จ์ ํ ์คํธ๋ฅผ ๋ง๋ค์ด ๋ณด๋๋ก ํ์.
void main() {
test("์ด๊ธฐ ๊ฐ์ด 0์ธ๊ฐ ?", () {
final Counter _counter = Counter();
expect(_counter.value, 0);
});
test("์ฆ๊ฐ ํ๋๊ฐ ?", () {
final Counter _counter = Counter();
_counter.increment();
expect(_counter.value, 1);
});
test("๊ฐ์ ํ๋๊ฐ ?", () {
final Counter _counter = Counter();
_counter.decrement();
expect(_counter.value, -1);
});
}
์ฝ๋๋ฅผ ์คํ ํด๋ณด๋ฉด, ์ ์์ ์ผ๋ก Counter ๊ธฐ๋ฅ์ ๋ํ ํ ์คํธ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์๋ค.
์ด๋ฒ์ Person ํด๋์ค๋ฅผ ์์ฑํด์ฃผ๊ณ , ์ด๋ฆ์ ๋ณ๊ฒฝํ ์ ์๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํ์ฌ Person ํด๋์ค์ ๋ํ ๋จ์ ํ ์คํธ๋ฅผ ์งํํด๋ณด์.
class Person {
String? name;
void changedName(String name) => this.name = name;
}
์ด๊ธฐ ๊ฐ์ด NULL์ธ์ง์ changedName ๊ธฐ๋ฅ์ ์ฌ์ฉํด name์ ๋ณ๊ฒฝํ ์ ์๋์ง ํ ์คํธ ์กฐ๊ฑด์ ์คํํด ๋ณด์.
void main() {
group("Person ๊ธฐ๋ฅ ํ
์คํธ", () {
test("์ด๊ธฐ ๊ฐ์ด NULL ์ธ๊ฐ ?", () {
final Person _person = Person();
expect(_person.name, null);
});
test("์ด๋ฆ์ ๋ณ๊ฒฝํ ์ ์๋๊ฐ ?", () {
final Person _person = Person();
const String name = "TYGER";
_person.changedName(name);
expect(_person.name, name);
});
});
}
์ด์ฒ๋ผ ์ ๋ ํ ์คํธ๋ ์์ ๋จ์์ ํด๋์ค๋ ๋ฉ์๋, ๊ฐ๋ณ ํจ์๋ฑ์ ํ ์คํธ๋ฅผ ์งํํ ์ ์๋๋ก ์ง์ํ๊ณ ์์ด ํ ์คํธ ์ผ์ด์ค๋ฅผ ์ถ๊ฐํด ๊ธฐ๋ฅ์ ์ ๊ฒํ ์ ์๋ค.
์ด์ด์ Widget Test์ ๋ํด์ ์ดํด๋ณด๋๋ก ํ๊ฒ ๋ค.
Widget Test๋ ๊ฐ๋ณ ์์ ฏ์ ํ ์คํธํ ์ ์๋ ๋ฐฉ๋ฒ์ผ๋ก, Unit Test์ Intergration Test์ ์ค๊ฐ ์ ๋์ ์์น์์ ํ ์คํธ๋ฅผ ์งํํ๊ฒ ๋๋ค.
UI๋ฅผ ํ ์คํธํ ์ ์๋ ๋ฐฉ๋ฒ์ผ๋ก ๊ฐ๋ณ ์์ ฏ์ด๋ ์์ ฏ ํธ๋ฆฌ์ ๋ํ ํ ์คํธ๋ผ๊ณ ๋ณด๋ฉด ๋๋ค.
์์ ฏ ํ ์คํธ๋ฅผ ์ํด์๋ ๋จ์ ํ ์คํธ์์ ์ฌ์ฉํ๋ test ํจ์๊ฐ ์๋ testWidgetsํจ์๋ฅผ ์ฌ์ฉํด ํ ์คํธ๋ฅผ ์งํํ๊ฒ ๋๋ค.
testWidgets ํจ์์ ๊ธฐ๋ฅ์ด test ํจ์์ ๊ฑฐ์ ๋์ผํ์ง๋ง, callback ๋ถ๋ถ์ ๋ํ ์ฐจ์ด๊ฐ ์๋ค.
void testWidgets(
String description,
Future<void> Function(WidgetTester) callback, {
bool? skip,
Timeout? timeout,
bool semanticsEnabled = true,
TestVariant<Object?> variant = const DefaultTestVariant(),
dynamic tags,
int? retry,
})
callback์ ๋ณด๋ฉด WidgetTester ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํด ์์ ฏ์ ๋ํ ๋น๋ ๋ฐ ์ํธ์์ฉ์ ํตํด ๋น๋๊ธฐ์ ์ผ๋ก ํ ์คํธ๋ฅผ ํ ์ ์๋๋ก ํด์ค๋ค.
๊ฐ๋จํ UI๋ฅผ ๊ตฌ์ฑํด๋ณด๋๋ก ํ๊ฒ ๋ค. count ๋ณ์๋ฅผ ์ฌ์ฉํด ๊ฐ์ ์ฆ๊ฐ ๋๋ ๊ฐ์ ์ํค๊ณ , ์ด๊ธฐํํ ์ ์๋ ๊ธฐ๋ฅ์ ๊ฐ์ถ ๊ตฌ์กฐ์ด๋ค.
์ด์ ํด๋น ์์ ฏ์ ํ ์คํธ๋ฅผ ์งํํด๋ณด์.
ํ ์คํธ๋ฅผ ์งํํ ์์ ฏ์ ์ด๊ธฐ ๋น๋ํ๊ธฐ ์ํด WidgetTester ๊ฐ์ฒด์ ๊ธฐ๋ฅ์ธ pumpWidget ํจ์๋ฅผ ์ฌ์ฉํด์ฃผ๋ฉด ๋๋ค.
์ฌ๊ธฐ์ ์ค์ํ ์ ์ pumpWidget์์ ํ ์คํธ ํ ์์ ฏ์ ์คํํ ๋์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ ๊ฒฝ์ฐ๋ผ๋ฉด ๊ฑฐ์ ๋๋ถ๋ถ์ด Directionality ์์ ฏ์ ํฌํจํ์ง ๋ชปํ์ฌ์ ๋ฐ์ํ๋ ์ค๋ฅ๊ธฐ ๋๋ฌธ์, Directionality ์์ ฏ์ ์๋์ผ๋ก ํฌํจํ๋ MaterialApp ์์ ฏ์ ์ต์์ ์์ ฏ์ผ๋ก ๊ฐ์ธ์ ํ ์คํธ๋ฅผ ํ๋ฉด ๋๋ค.
main() {
testWidgets("CountWidget Test", (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(home: CountWidget()));
expect(find.text("0"), findsOneWidget);
expect(find.text("1"), findsNothing);
expect(find.text("-1"), findsNothing);
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
expect(find.text("1"), findsOneWidget);
});
}
pumpWidget์ผ๋ก ์ด๊ธฐ ๋น๋๋ฅผ ํด์ฃผ๊ณ ํ ์คํธ ์กฐ๊ฑด์ ๋ฃ์ด์ฃผ๋ฉด ๋๋ค.
ํ ์คํธ๋ ๋จ์ ํ ์คํธ์ ๋์ผํ๊ฒ expect ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
์์ ฏ์ด ์ด๊ธฐ ๋๋๋ง๋๊ณ ๋๋ฉด, find๋ฅผ ์ฌ์ฉํด ๋๋๋ง๋ ํ ์คํธ๋ฅผ ์ฐพ์ ์ ์๋ค.
count ๋ณ์๋ 0์ผ๋ก ์ด๊ธฐํ๋์ ์คํ๋๊ธฐ ๋๋ฌธ์, findsOneWidget์ ๊ฐ์ด 0์ธ์ง๋ฅผ ํ์ธํ์ฌ ํ ์คํธ๋ฅผ ํ ์ ์๋ค.
findsNothing์ ๋๋๋ง ๋ ํ ์คํธ์ ๊ฐ์ด 1์ด๋ -1์ด ์๋ ์กฐ๊ฑด์ ํ ์คํธํ๋ ๊ฒ์ด๋ค.
expect(find.text("0"), findsOneWidget);
expect(find.text("1"), findsNothing);
expect(find.text("-1"), findsNothing);
์ด์ด์ WidgetTester ๊ฐ์ฒด์ tap ๊ธฐ๋ฅ์ ์ฌ์ฉํด ํน์ ๋ฒํผ์ ํญํ ์ ์๋ค.
find.byIcon์ ์ฌ์ฉํด ์ฆ๊ฐ ์์ด์ฝ์ ์ฐพ์์ ํญ์ ํด์ค๋ค.
await tester.tap(find.byIcon(Icons.add));
์์ ฏ ํ ์คํธ์์๋ ์์ ฏ์ ์๋์ผ๋ก ๋ค์ ๋๋๋ง ํ ์ ์๊ธฐ ๋๋ฌธ์ pump ํจ์๋ก ๋ณ๊ฒฝ๋ ์์ ฏ์ ๋๋๋ง ํ ์ ์๋๋ก ํด์ฃผ์ด์ผ ํ๋ค.
await tester.pump();
๋ง์ง๋ง์ผ๋ก ๋ณ๊ฒฝ๋ ํ ์คํธ๊ฐ 1์ธ์ง๋ฅผ ํ ์คํธํด๋ณด์.
expect(find.text("1"), findsOneWidget);
์ด๋ฒ์๋ ์กฐ๊ฑด์ ๋ ์ถ๊ฐํด ๋ณด๋๋ก ํ์.
main() {
testWidgets("CountWidget Test", (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(home: CountWidget()));
// count ๊ฐ์ด 0์ธ์ง
expect(find.text("0"), findsOneWidget);
// count ๊ฐ์ด 1์ด ์๋์ง
expect(find.text("1"), findsNothing);
// count ๊ฐ์ด -1์ด ์๋์ง
expect(find.text("-1"), findsNothing);
// ์ฆ๊ฐ ๋ฒํผ ํด๋ฆญ
await tester.tap(find.byIcon(Icons.add));
// ์์ ฏ ์
๋ฐ์ดํธ
await tester.pump();
// count ๊ฐ์ด 1์ธ์ง
expect(find.text("1"), findsOneWidget);
// ๊ฐ์ ๋ฒํผ 2๋ฒ ํด๋ฆญ
await tester.tap(find.byIcon(Icons.remove));
await tester.tap(find.byIcon(Icons.remove));
// ์์ ฏ ์
๋ฐ์ดํธ
await tester.pump();
// count ๊ฐ์ด -1์ธ์ง
expect(find.text("-1"), findsOneWidget);
// ์ด๊ธฐํ ๋ฒํผ ํด๋ฆญ
await tester.tap(find.byIcon(Icons.refresh));
await tester.pump();
// count ๊ฐ์ด 0์ธ์ง
expect(find.text("0"), findsOneWidget);
});
}
์ด์ด์ ์คํฌ๋กค ๊ธฐ๋ฅ์ด ํฌํจ๋ ์์ ฏ ํ ์คํธ๋ฅผ ์งํํด๋ณด์.
20๊ฐ์ ์์ดํ ์ ๋ฆฌ์คํธ๋ก ๋ณด์ฌ์ฃผ๊ณ ๊ฐ ์์ดํ ์ ํด๋ฆญํ๋ฉด ์๋จ์ผ๋ก ์์ดํ ์ ์ด๋์์ผ ์ฃผ๋ ๊ตฌ์กฐ์ด๋ค.
ํ ์คํธ ์ฝ๋๋ฅผ ๋ณด๋ฉด drag ๊ธฐ๋ฅ์ ์ฌ์ฉํด ํน์ ์์น๊น์ง ์คํฌ๋กค์ ์ด๋ํ ์ ์์ผ๋ฉฐ, ์คํฌ๋กค๊ณผ ๊ฐ์ ์ ๋๋ฉ์ด์ ์ ํ ์คํธ ํ๋ ๊ฒฝ์ฐ์๋ pumpAndSettle ๊ธฐ๋ฅ์ ์ฌ์ฉํด ์ ๋๋ฉ์ด์ ์ ์๋ฃ ์์ ๊น์ง ๊ธฐ๋ค๋ ค์ผ ๋ค์ ํ ์คํธ๊ฐ ๋ฌธ์ ์์ด ์งํํ ์ ์๋ค.
void main() {
testWidgets("ScrollWidget Test", (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(home: ScrollWidget()));
// ์ด๊ธฐ ์๋จ ์์ดํ
์ด Item 1 ์ธ์ง ํ์ธ
expect(find.text("Item 1"), findsWidgets);
// Item 2 ์์ดํ
ํด๋ฆญ
await tester.tap(find.text("Item 2"));
await tester.pump();
// ์๋จ ์์ดํ
์ด Item 2์ธ์ง ํ์ธ
expect(find.text("Item 2"), findsWidgets);
// Item 2๋ฅผ ์ฐพ์ y์ถ์ผ๋ก -250 ํฝ์
์คํฌ๋กค
await tester.drag(find.text("Item 2"), const Offset(0, -250));
// ์ ๋๋ฉ์ด์
๋๋ ๋๊น์ง ๋๊ธฐ
await tester.pumpAndSettle();
// ์๋จ ์์ดํ
์ด Item 5์ธ์ง ํ์ธ
expect(find.text("Item 5"), findsOneWidget);
});
}
์์ ฏ ํ ์คํธ๋ ๋ค์ํ UI ํ ์คํธ๋ฅผ WidgetTester ๊ฐ์ฒด๋ฅผ ํตํด์ ํ ์คํธ๋ฅผ ์งํํ ์ ์์ผ๋, Flutter ์ฑ ํ ์คํธ์ ๋ํ ๋ํ๋จผํธ ์ฐธ๊ณ ํ์๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค.
๋ง์ง๋ง์ผ๋ก Intergration Test์ ๋ํด์ ์์๋ณด์.
ํตํฉ ํ ์คํธ๋ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ฑ ์์๋ค์ ๊ฒฐํฉํ์ฌ ์ ์ฒด ์์คํ ์ด ์์๋๋ก ์๋ํ๋์ง ํ์ธํ๋ ๋ฐฉ๋ฒ์ผ๋ก, ์ค์ ์ฌ์ฉ์ ์๋๋ฆฌ์ค๋ฅผ ์๋ฎฌ๋ ์ด์ ํ๊ณ ํ๋ฉด ๊ฐ์ ๋ค๋น๊ฒ์ด์ ์ฒ๋ฆฌ ๋ฐ ๋ฐ์ดํฐ ํ๋ฆ, ์ฌ์ฉ์ ์ ๋ ฅ ์ฒ๋ฆฌ ๋ฑ์ ํฌํจํ ์ ์ฒด ์ฑ์ ๋์์ ๊ฒ์ฆํ๊ฒ ๋๋ค.
์์ ฏ ํ ์คํธ์ ์ ๋ ํ ์คํธ ๋จ๊ณ์์ ํ ์คํธํ์ง ๋ชปํ๋ ํ๋ฌ๊ทธ์ธ, API ๋ฑ์ ์ธ๋ถ ์์กด์ฑ์ ํฌํจํ์ฌ ์ ์ฒด๋ฅผ ํ ์คํธํ ์ ์์ด ์์ ์ฑ์ ๋ณด์ฅํ๋ ๋ฐ ์ค์ํ ์ญํ ์ ํ์ง๋ง, ํ ์คํธ ๊ตฌ์กฐ์ ๋ณต์ก์ฑ์ด ์ปค์ง๊ณ ์ด์ ๋ฐ๋ฅธ ์๊ฐ ์์๊ฐ ๋ง์์ง๋ค๋ ๋จ์ ๋ ์๋ค.
ํตํฉ ํ ์คํธ ์งํ์ ์ํด ํจํค์ง๋ฅผ ์ถ๊ฐํด ์ฃผ๋๋ก ํ์.
dev_dependencies:
integration_test:
sdk: flutter
์ด๋ฒ ํตํฉ ํ ์คํธ์ ์ฌ์ฉํ UI๋ Flutter ํ๋ก์ ํธ ์์ฑ์ ์๋์ผ๋ก ๋ง๋ค์ด์ ธ ์๋ CountApp์ ์ฌ์ฉํ๋๋ก ํ๊ฒ ๋ค.
ํ๋ก์ ํธ ํด๋ ์๋์ intergration_test ํด๋๋ฅผ ์์ฑํ๊ณ app_test.dart ํ์ผ์ ์๋์ ๊ฐ์ด ์์ฑํด์ฃผ์.
ํ ์คํธ ์ฝ๋๋ฅผ ์ถ๊ฐํด ์ฃผ๋๋ก ํ์.
ํตํฉ ํ ์คํธ๋ฅผ ์ํ ์ํธ๋ฆฌ ํฌ์ธํธ๋ก main ํจ์๋ฅผ ์คํ์์ผ์ผ ํ๊ธฐ ๋๋ฌธ์ ์๋์ ๊ฐ์ด main์ ์ถ๊ฐํด ์ฃผ๋๋ก ํ์.
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:test_code_sample/main.dart' as app;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group("End to End Test", () {
testWidgets("Count App", (tester) async {
app.main();
await tester.pumpAndSettle();
expect(find.text("0"), findsOneWidget);
final Finder fab = find.byTooltip("Increment");
await tester.tap(fab);
await tester.pumpAndSettle();
expect(find.text("1"), findsOneWidget);
});
});
}
ํตํฉ ํ ์คํธ๋ฅผ ์คํํ๊ธฐ ์ํด์๋ ์ค์ ๋๋ฐ์ด์ค๋ ์๋ฎฌ๋ ์ดํฐ์์ ์คํํด์ผ ํ๊ธฐ ๋๋ฌธ์ ์ฐ๊ฒฐ ํ ์๋ ํฐ๋ฏธ๋ ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํด์ ์คํํ๊ฑฐ๋ IDE์์ ์คํ์ ํด์ฃผ๋ฉด ๋๋ค.
flutter test integration_test/app_test.dart
๋ชจ๋ ํ ์คํธ๊ฐ ์๋ฃ๋๋ฉด ์๋์ ๊ฐ์ด ํ ์คํธ๊ฐ ์คํ์ด ๋๊ณ , ์ค์ ๋น๋๋ ์ฑ์์ ์นด์ดํธ๊ฐ 1์ด ์ฆ๊ฐ๋ ์ํ๋ก ํ ์คํธ๊ฐ ์๋ฃ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ง๊ธ์ ๋จ์ํ ์ฑ์ ํตํฉ ํ ์คํธ๋ง์ ์งํํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ ๊ฒ์ด ๋ง์ง ์์์ง๋ง ์ค์ ์๋น์ค๋ฅผ ๊ฐ๋ฐํ๊ธฐ ์ํด์ ํตํฉ ํ ์คํธ ํ๊ฒฝ์ ๋ง๋๋ ๊ฒ์ ์ฌ์ด ์์ ์ ์๋๋ค.
ํตํฉ ํ ์คํธ์ ์ฌ์ฉ๋์ด ์ง๋ ํ ์คํธ ์ฝ๋๋ค์ ์์์ ์ดํด๋ณธ ์์ ฏ ํ ์คํธ์ ์ ๋ ํ ์คํธ์์ ์ฌ์ฉํ ๋ฐฉ๋ฒ์ ๊ฒฐํฉํด์ ๊ตฌ์ฑํด์ฃผ๋ฉด ๋๋ค.
๊ฐ๋จํ๊ฒ Flutter์์ ์ฑ ํ ์คํ ์ ์ํ ๋ฐฉ๋ฒ์ธ ๋จ์, ์์ ฏ, ํตํฉ ํ ์คํธ์ ๋ํ ํ๊ฒฝ ๊ตฌ์ฑ ๋ฐ ์ฝ๋ ์์ฑ ๋ฐฉ๋ฒ๊ณผ ํ ์คํธ์ ๋ํ ๋ถ๋ถ์ ๋ค๋ค๋ดค๋ค.
์์ง์ ์ฑ ํ ์คํ ์ ์ค์ ๋ก ์๋น์ค์ ์ด๋ป๊ฒ ์ ์ฉํด์ผ ํ๋์ง ๊ฐ์ด ์ ์ค์ง ์์ ์๋ ์์ ๊ฒ์ด๋ค. ๋น์ฐํ ๊ฒ์ด๋ค.
์๋น์ค ๊ฐ๋ฐ์ ์์ด ํ ์คํธ ์ผ์ด์ค๋ฅผ ๊ตฌ์ฑํ๋ ์์ ์ ๊ฒฐ์ฝ ์ฌ์ด์ผ์ ์๋๊ธฐ์ ์ฒ์ฒํ ๋จ์ํ ๊ธฐ๋ฅ๋ถํฐ ๊ตฌ์กฐ๋ฅผ ๋ง๋ค์ด๊ฐ๋ฉด์ ์ฐ์ตํ๋ฉด ๋๋ค.
๋ค์์๋ ์๋น์ค๋ฅผ ๋ง๋ค๋ฉด์ ํ ์คํธ ์ฝ๋๋ฅผ ๊ตฌ์ฑํ๋ ๋ฐฉ๋ฒ๋ก ์ ๋ํด์ ๋ค๋ค๋ณด๋ฉด์ ์ค์ ์๋น์ค์ ์ ์ฉํด ๋ณผ ์ ์๋๋ก ๊ธ์ ์์ฑํ ์์ ์ด๋ค.
๊ฐ์ฌํฉ๋๋ค !