๐Ÿงช [Flutter] ์•ฑ ํ…Œ์ŠคํŠธ ์œ ํ˜• ๋ฐ ๋ฐฉ๋ฒ• ์‚ดํŽด๋ณด๊ธฐ (Unit, Widget, Intergration)

Tygerยท2024๋…„ 6์›” 9์ผ
1

Flutter

๋ชฉ๋ก ๋ณด๊ธฐ
61/64
post-custom-banner

๐Ÿงช ์•ฑ ํ…Œ์ŠคํŠธ ์œ ํ˜• ๋ฐ ๋ฐฉ๋ฒ• ์‚ดํŽด๋ณด๊ธฐ (Unit, Widget, Intergration)

Testing Flutter Apps | Flutter

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Flutter์—์„œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ…Œ์ŠคํŒ…ํ•˜๋Š” ๋ฐฉ๋ฒ• ๋ฐ ์œ ํ˜•์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

Flutter๋„ ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ ์–ธ์–ด์ฒ˜๋Ÿผ ๊ฐœ๋ฐœํ•œ ๊ธฐ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•˜๊ฑฐ๋‚˜, ๋งŒ๋“ค๊ณ ์ž ํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์ „์— ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•ด์ฃผ๊ณ  ์žˆ๋‹ค.

ํ…Œ์ŠคํŠธ๋Š” ํ•„์ˆ˜๊ฐ€ ์•„๋‹Œ ์„ ํƒ์˜ ์˜์—ญ์ด๋‹ค ๋ณด๋‹ˆ, ๋ชจ๋“  ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ๊ณ  ์ผ๋ถ€ ๊ธฐ๋Šฅ๋งŒ ํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ๊ณ  ์‹ฌ์ง€์–ด๋Š” ์•„์˜ˆ ์ฝ”๋“œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜์ง€ ์•Š๋Š” ์„œ๋น„์Šค๋„ ์žˆ๋‹ค.

์ด์ฒ˜๋Ÿผ ์„ ํƒ์˜ ์˜์—ญ์ด๋‹ค ๋ณด๋‹ˆ ์‹œ๊ฐ„์„ ํˆฌ์žํ•˜๋ฉด์„œ ๊นŒ์ง€ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ƒ๊ฐํ•˜๊ณ  ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ๋ถˆํ•„์š”ํ•˜๋‹ค๊ณ  ๋Š๋ผ๋Š” ๊ฐœ๋ฐœ์ž๋„ ์žˆ๊ณ , ์ถ”ํ›„์— ์„œ๋น„์Šค๊ฐ€ ํ™•๋Œ€๋จ์— ๋”ฐ๋ผ ์ˆ˜์ •๋œ ์˜์—ญ์˜ ์ฝ”๋“œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋Š” ์ง€๋ฅผ ๋ฏธ๋ฆฌ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•˜์—ฌ ๋‚˜์ค‘์— ๋ฐœ์ƒํ•  ์ˆ˜๋„ ์žˆ๋Š” ์‹œ๊ฐ„์„ ๋‹จ์ถ•ํ•˜๋Š” ๊ฒƒ์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๊ฐœ๋ฐœ์ž๋„ ์žˆ๋‹ค.

๊ฒฝํ—˜ํ•˜๊ฑฐ๋‚˜ ๋‹น์žฅ์— ์‚ฌ์šฉํ•˜์ง€ ์•Š๋”๋ผ๋„ Flutter์—์„œ๋Š” ์–ด๋–ป๊ฒŒ ์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ณ  UI๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š”์ง€ ์•Œ์•„๋‘ฌ์„œ ๋‚˜์  ๊ฒƒ์€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋ณ๊ฒŒ ์ฝ์–ด๋ณด์‹œ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

App Testing ?

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ…Œ์ŠคํŒ…์„ ์™œ ํ•ด์•ผํ•˜๋Š” ๊ฑธ๊นŒ ?

์ž์ฒด์ ์œผ๋กœ QA๋ฅผ ์ง„ํ–‰ํ•˜๋Š”๋ฐ, ์™œ ๋ณ„๋„๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ…Œ์ŠคํŒ…๋„ ์ง„ํ–‰ ํ•ด์•ผ๋งŒ ํ•˜๋Š” ๊ฑด์ง€๋Š” ๋‹น์—ฐํ•œ ์ด์œ ์ด๊ฒ ์ง€๋งŒ ์•ฑ์˜ ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋  ๋•Œ๋งˆ๋‹ค ์ „์ฒด ์˜์—ญ์˜ ์ฝ”์–ดํ•œ ๊ธฐ๋Šฅ๋“ค์— ๋Œ€ํ•ด์„œ๊นŒ์ง€ QA๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๋งŽ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐœ๋ฐœ๋‹จ์—์„œ ์‚ฌ์ „์— ์ฝ”๋“œ์— ๋ฌธ์ œ๊ฐ€ ์—†๋Š”์ง€, ์ถ”๊ฐ€๋œ ์ฝ”๋“œ๋กœ ์ธํ•˜์—ฌ ๊ธฐ์กด์˜ ๊ธฐ๋Šฅ์—๋„ ๋ฌธ์ œ๊ฐ€ ์—†๋Š”์ง€๋ฅผ ์ž๋™์œผ๋กœ ํ…Œ์ŠคํŒ…์„ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ์ฝ”๋“œ ํ…Œ์ŠคํŒ…์„ ์ง„ํ–‰ํ•˜๋Š” ๋ชฉ์ ์€ ์—ฌ๋Ÿฌ๊ฐ€์ง€๊ฐ€ ์žˆ๊ฒ ์ง€๋งŒ, ๋ฒ„๊ทธ ๋ฐ ์ฝ”๋“œ์˜ ๊ฒฐํ•จ์„ ์—†์• ๊ณ  ๊ฐœ๋ฐœ์ž๊ฐ€ ์˜๋„ํ•œ ๋Œ€๋กœ ๊ธฐ๋Šฅ์ด ์ˆ˜ํ–‰์„ ์‹œํ‚ค๋ฉฐ ๋‹ค์–‘ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์„œ๋น„์Šค๊ฐ€ ์•ˆ์ •์ ์œผ๋กœ ๊ตฌ๋™์ด ๋˜๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๊ฒŒ ๋œ๋‹ค. ๋˜ํ•œ ์ดˆ๊ธฐ์—๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด์„œ ๊ฐœ๋ฐœ ์†๋„๊ฐ€ ๋Šฆ์–ด์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ ์ถ”ํ›„์— ์ž๋™ํ™”๋œ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ๋ฐ˜๋ณต์ ์ธ ์ˆ˜์ž‘์—… ํ…Œ์ŠคํŠธ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์–ด ์†๋„๋ฅผ ๋†’ํž ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ž‘์„ฑ๋œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ๊ธฐ๋Šฅ์„ ๋ฌธ์„œํ™”ํ•˜๋Š”๋ฐ ๋„์›€์ด ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

์ฆ‰, ๋‹จ์ˆœํ•œ ์ด์Šˆ๋ฅผ ์ฐพ์•„๋‚ด๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ „๋ฐ˜์ ์ธ ํ’ˆ์งˆ ๋ฐ ๊ฒ€์ฆ์„ ํ•˜๋Š” ์ ˆ์ฐจ๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด์„œ๋Š” ํŒจํ‚ค์ง€ ์ถ”๊ฐ€๊ฐ€ ํ•„์š”ํ•œ๋ฐ, ํ•ด๋‹น ํŒจํ‚ค์ง€๋Š” ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ์‹œ ์ž๋™ ์ถ”๊ฐ€๋œ ํŒจํ‚ค์ง€๋ผ ์—†๋‹ค๋ฉด ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.

dependencies

flutter_test ํŒจํ‚ค์ง€๋Š” ๊ฐœ๋ฐœ์‹œ์—๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๊ธฐ์— dev_dependencies์— ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

dev_dependencies:
  flutter_test:
    sdk: flutter

Test File

ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ํ…Œ์ŠคํŠธ ๊ด€๋ จ ํŒŒ์ผ๋“ค์€ ๋ฐ˜๋“œ์‹œ test ํด๋”์•ˆ์— ๋„ฃ์–ด์•ผ๋งŒ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋‹ˆ ์—†๋‹ค๋ฉด test ํด๋”๋ฅผ ์ƒ์„ฑํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค.


Flutter์—์„œ๋Š” Unit, Widet(UI), Intergration ์ด๋ ‡๊ฒŒ 3๊ฐ€์ง€ ์œ ํ˜•์˜ ํ…Œ์ŠคํŒ…์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๊ณ  ์žˆ๋‹ค.

์ด์ œ ๊ฐ๊ฐ์˜ ํ…Œ์ŠคํŒ… ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ๋‹ค๋ค„๋ณด๋„๋ก ํ•˜์ž.

Unit Test

์ฒซ ๋ฒˆ์งธ๋กœ ์‚ดํŽด๋ณผ ํ…Œ์ŠคํŒ… ๋ฐฉ๋ฒ•์€ Unit Test์ด๋‹ค.

Unit Test๋Š” ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ผ๊ณ  ํ•˜๋ฉฐ ๊ฐœ๋ณ„ ํ•จ์ˆ˜, ๋ฉ”์„œ๋“œ, ํด๋ž˜์Šค ๋“ฑ์˜ ์ž‘์€ ์ฝ”๋“œ ๋‹จ์œ„๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ํ…Œ์ŠคํŠธํ•˜์—ฌ ๋ฒ„๊ทธ๋ฅผ ์‚ฌ์ „์— ๊ฐœ์„ ํ•ด ์ฝ”๋“œ์˜ ํ’ˆ์งˆ๊ณผ ์•ˆ์ •์„ฑ์„ ๋†’์ด๋Š” ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•์ด๋‹ค.

๋จผ์ € ๊ฐ„๋‹จํ•œ ์œ ๋‹› ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด๋ณด์ž.

test ํŒŒ์ผ์—์„œ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด๋ณด์ž.

void main() {
  test("Unit Testing", () => expect(1 + 1, 2));
}

์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ์—๋Š” "Run"์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. ํ…Œ์ŠคํŒ… ๊ฒฐ๊ณผ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์„ฑ๊ณตํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ฒดํฌ ํ‘œ์‹œ๊ฐ€ ํ‘œ๊ธฐ ๋œ๋‹ค.

๋กœ๊ทธ์ฐฝ์—์„œ๋„ ํ…Œ์ŠคํŠธ ์‹คํ–‰์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

์‹คํŒจ๊ฐ€ ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ ?

๊ฐ•์ œ๋กœ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๊ฐ€ ์‹คํŒจ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋„๋ก ๊ฒฐ๊ณผ ๊ฐ’์„ ์ˆ˜์ •ํ•˜์—ฌ ์ง„ํ–‰ํ•ด๋ณด์ž.

์‹คํŒจ๊ฐ€ ๋˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์‹คํŒจ๊ฐ€ ๋œ ๋ถ€๋ถ„์ด ์–ด๋–ค ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์ธ์ง€๋ฅผ ํฌ์ธํŠธ๋กœ ๋ณด์—ฌ์ฃผ๋ฉด์„œ, X ์•„์ด์ฝ˜์ด ํ‘œ๊ธฐ ๋œ๋‹ค.

์ด์ œ ํ…Œ์ŠคํŠธ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•˜๋Š”์ง€ ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ดํŽด๋ดค์œผ๋‹ˆ, ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.

test

๋จผ์ € 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
});

expect

์ด์–ด์„œ 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

์—ฌ๋Ÿฌ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋“ค์„ ๊ทธ๋ฃน์œผ๋กœ ๊ด€๋ฆฌํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

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์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

Widget Test๋Š” ๊ฐœ๋ณ„ ์œ„์ ฏ์„ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ, Unit Test์™€ Intergration Test์˜ ์ค‘๊ฐ„ ์ •๋„์˜ ์œ„์น˜์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.

UI๋ฅผ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐœ๋ณ„ ์œ„์ ฏ์ด๋‚˜ ์œ„์ ฏ ํŠธ๋ฆฌ์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ๋ผ๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.

์œ„์ ฏ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด์„œ๋Š” ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋˜ test ํ•จ์ˆ˜๊ฐ€ ์•„๋‹Œ testWidgetsํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.

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

๋งˆ์ง€๋ง‰์œผ๋กœ Intergration Test์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ์„ฑ ์š”์†Œ๋“ค์„ ๊ฒฐํ•ฉํ•˜์—ฌ ์ „์ฒด ์‹œ์Šคํ…œ์ด ์˜ˆ์ƒ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ, ์‹ค์ œ ์‚ฌ์šฉ์ž ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๊ณ  ํ™”๋ฉด ๊ฐ„์˜ ๋„ค๋น„๊ฒŒ์ด์…˜ ์ฒ˜๋ฆฌ ๋ฐ ๋ฐ์ดํ„ฐ ํ๋ฆ„, ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์ฒ˜๋ฆฌ ๋“ฑ์„ ํฌํ•จํ•œ ์ „์ฒด ์•ฑ์˜ ๋™์ž‘์„ ๊ฒ€์ฆํ•˜๊ฒŒ ๋œ๋‹ค.

์œ„์ ฏ ํ…Œ์ŠคํŠธ์™€ ์œ ๋‹› ํ…Œ์ŠคํŠธ ๋‹จ๊ณ„์—์„œ ํ…Œ์ŠคํŠธํ•˜์ง€ ๋ชปํ•˜๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ, API ๋“ฑ์˜ ์™ธ๋ถ€ ์˜์กด์„ฑ์„ ํฌํ•จํ•˜์—ฌ ์ „์ฒด๋ฅผ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์–ด ์•ˆ์ •์„ฑ์„ ๋ณด์žฅํ•˜๋Š” ๋ฐ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•˜์ง€๋งŒ, ํ…Œ์ŠคํŠธ ๊ตฌ์กฐ์˜ ๋ณต์žก์„ฑ์ด ์ปค์ง€๊ณ  ์ด์— ๋”ฐ๋ฅธ ์‹œ๊ฐ„ ์†Œ์š”๊ฐ€ ๋งŽ์•„์ง„๋‹ค๋Š” ๋‹จ์ ๋„ ์žˆ๋‹ค.

Dependencies

ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์ง„ํ–‰์„ ์œ„ํ•ด ํŒจํ‚ค์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด ์ฃผ๋„๋ก ํ•˜์ž.

dev_dependencies:
  integration_test:
    sdk: flutter

์ด๋ฒˆ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์— ์‚ฌ์šฉํ•  UI๋Š” Flutter ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ์‹œ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด์ ธ ์žˆ๋Š” CountApp์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜๊ฒ ๋‹ค.

ํ”„๋กœ์ ํŠธ ํด๋” ์•„๋ž˜์— intergration_test ํด๋”๋ฅผ ์ƒ์„ฑํ•˜๊ณ  app_test.dart ํŒŒ์ผ์„ ์•„๋ž˜์™€ ๊ฐ™์ด ์ƒ์„ฑํ•ด์ฃผ์ž.

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์—์„œ ์•ฑ ํ…Œ์ŠคํŒ…์„ ์œ„ํ•œ ๋ฐฉ๋ฒ•์ธ ๋‹จ์œ„, ์œ„์ ฏ, ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•œ ํ™˜๊ฒฝ ๊ตฌ์„ฑ ๋ฐ ์ฝ”๋“œ ์ž‘์„ฑ ๋ฐฉ๋ฒ•๊ณผ ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•œ ๋ถ€๋ถ„์„ ๋‹ค๋ค„๋ดค๋‹ค.

์•„์ง์€ ์•ฑ ํ…Œ์ŠคํŒ…์„ ์‹ค์ œ๋กœ ์„œ๋น„์Šค์— ์–ด๋–ป๊ฒŒ ์ ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€ ๊ฐ์ด ์ž˜ ์˜ค์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ๋‹น์—ฐํ•œ ๊ฒƒ์ด๋‹ค.

์„œ๋น„์Šค ๊ฐœ๋ฐœ์— ์žˆ์–ด ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์ž‘์—…์€ ๊ฒฐ์ฝ” ์‰ฌ์šด์ผ์€ ์•„๋‹ˆ๊ธฐ์— ์ฒœ์ฒœํžˆ ๋‹จ์ˆœํ•œ ๊ธฐ๋Šฅ๋ถ€ํ„ฐ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์–ด๊ฐ€๋ฉด์„œ ์—ฐ์Šตํ•˜๋ฉด ๋œ๋‹ค.

๋‹ค์Œ์—๋Š” ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค๋ฉด์„œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•๋ก ์— ๋Œ€ํ•ด์„œ ๋‹ค๋ค„๋ณด๋ฉด์„œ ์‹ค์ œ ์„œ๋น„์Šค์— ์ ์šฉํ•ด ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ๊ธ€์„ ์ž‘์„ฑํ•  ์˜ˆ์ •์ด๋‹ค.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค !

[Github] Sample Code

profile
Flutter Developer
post-custom-banner

0๊ฐœ์˜ ๋Œ“๊ธ€