Skip to content

๐Ÿค– AN ํ…Œ์ŠคํŠธ ์ „๋žต

JUNWON LEE edited this page Oct 28, 2024 · 2 revisions

๐Ÿ”ˆ Test

  • Instrumentation Test: Espresso.
  • Integration Test: Robelectric
  • Unit Test: Kotest.
  • Test Double: Fake, Mockk

Unit Test ์ปจ๋ฒค์…˜

BDD ๊ธฐ๋ฒ• ์ค‘ Given-When-Then ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์„ฑํ•œ๋‹ค.

  1. given: ์‹œ๋‚˜๋ฆฌ์˜ค ์ง„ํ–‰์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ์ค€๋น„
  2. when: ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ง„ํ–‰ํ•˜๋Š”๋ฐ ํ•„์š” ์กฐ๊ฑด
  3. then: ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์™„๋ฃŒํ–ˆ์„ ๋•Œ ๋ณด์žฅํ•ด์•ผ ํ•˜๋Š” ๊ฒฐ๊ณผ
@Test
fun `test`() {
    // given
    val num1 = 1
    val num2 = 2
    // when
    val actual = sum(num1, num2)
    // then
    val expect = 3
    actual shouldBe expect
}
  • ViewModel Test ๋Š” ๋ฐ˜๋“œ์‹œ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.
  • ๊ทธ ์™ธ์˜ Test๋Š” ์ž‘์„ฑ์ž๊ฐ€ ์„ ํƒ์ ์œผ๋กœ ํ…Œ์ŠคํŠธํ•œ๋‹ค.
  • ์„ฑ๊ณต ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” **๋ฐ˜๋“œ์‹œ Fake ๊ฐ์ฒด**๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•œ๋‹ค.
  • ์˜ˆ์™ธ ์‹œ๋‚˜๋ฆฌ์˜ค์˜ ๊ฒฝ์šฐ๋Š” Mock์„ ํ™œ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•ด๋„ ๋œ๋‹ค.

ํ…Œ์ŠคํŠธ ๋”๋ธ”๋กœ Fake ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

  1. ์‹ค์ œ ๋™์ž‘๊ณผ ์œ ์‚ฌํ•œ ๋™์ž‘์„ ํ•˜๊ธฐ์— ์‹ ๋ขฐ์„ฑ ์žˆ๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์ œ๊ณต
  2. Unit Test ์™€ Android Test ์—์„œ ์žฌ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Œ

Fake ๊ฐ์ฒด๋Š” testing ๋ชจ๋“ˆ ์— ๋ชจ์•„๋‘์—ˆ์Šต๋‹ˆ๋‹ค.

Fake ๊ฐ์ฒด์™€ Mock ๊ฐ์ฒด ๋น„๊ต

๊ตฌ๋ถ„ Fake ๊ฐ์ฒด Mock ๊ฐ์ฒด
์ •์˜ Product ๊ฐ์ฒด๋ฅผ ๋ชจ๋ฐฉํ•œ ๊ฐ์ฒด๋กœ, ์‹ค์ œ ๋™์ž‘์„ ๋‹จ์ˆœํ™”ํ•œ ๊ตฌํ˜„์ฒด ํŠน์ • ํ–‰๋™์ด ์ผ์–ด๋‚ฌ๋Š”์ง€ ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ์ฒด๋กœ, ์˜ˆ์ƒ๋œ ํ˜ธ์ถœ๊ณผ ์‘๋‹ต์„ ๋ฏธ๋ฆฌ ์ •์˜
์ฃผ์šฉ๋„ ์‹ค์ œ ๋™์ž‘์„ ๋ชจ๋ฐฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ์˜ ์ถฉ์‹ค๋„์™€ ์‹ ๋ขฐ์„ฑ์„ ๋†’์ž„ ํ–‰๋™ ๊ฒ€์ฆ (Behavior Verification)
์žฅ์  - ๋†’์€ ํ…Œ์ŠคํŠธ ์ถฉ์‹ค๋„
- ๋‹ค์–‘ํ•œ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ
- ๊ฐ์ฒด์˜ ๋‚ด๋ถ€ ์ฝ”๋“œ๋ฅผ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๊ณ  ์‚ฌ์šฉ ๊ฐ€๋Šฅ (์ถ”์ƒํ™”, ์บก์Šํ™”)
- ํ…Œ์ŠคํŠธ ์‹œ ํ˜ธ์ถœ๋œ ๋ฉ”์„œ๋“œ์™€ ๊ทธ ์ˆœ์„œ๋ฅผ ๊ฒ€์ฆ ๊ฐ€๋Šฅ
- ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ๋ช…ํ™•ํ•˜๊ณ  ๊ตฌ์ฒด์ ์ž„
๋‹จ์  - ํ”„๋กœ๋•ํŠธ ์ฝ”๋“œ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด Fake๋„ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•จ (์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ ์ฆ๊ฐ€)
- Fake๋„ ์‹ค์ œ์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธ ํ•„์š”
- ์˜ˆ์ƒ๋œ ํ˜ธ์ถœ๊ณผ ์‘๋‹ต์„ ๋ฏธ๋ฆฌ ์ •์˜ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์„ค์ •์ด ๋ฒˆ๊ฑฐ๋กœ์›€
- ํ…Œ์ŠคํŠธ๊ฐ€ Mock ๊ฐ์ฒด์— ์˜์กดํ•˜๊ฒŒ ๋˜์–ด ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์Œ
์‚ฌ์šฉ ์‚ฌ๋ก€ - DB๋‚˜ Server ์™€์˜ ์˜์กด์„ฑ์„ ์ œ๊ฑฐํ•˜๊ณ  ๋…๋ฆฝ์ ์ธ ViewModel ํ…Œ์ŠคํŠธ ์ˆ˜ํ–‰
- ํŠน์ • ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€ ๊ฒ€์ฆ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ

Android Test

  • Product์šฉ Repository ๊ฐ€ ์•„๋‹Œ Fake Repository๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • Fake๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ค์šธ ๊ฒฝ์šฐ์—๋งŒ Mock ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•œ๋‹ค.
  • ํ™”๋ฉด๋ณ„ Portrait, Landscape ํ…Œ์ŠคํŠธ๋Š” ํ•„์ˆ˜๋‹ค.

Room Migration Test

ํ…Œ์ŠคํŠธ ์ž‘์„ฑ ๋ฐฉ๋ฒ• https://github.com/woowacourse-teams/2024-pokerogue-helper/pull/434 ์ฐธ๊ณ 

๋””๋น„ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•œ ์ดํ•ด๋ฅผ ์œ„ํ•ด ๊ฐ„๋‹จํ•˜๊ฒŒ ์ž‘์„ฑํ•ด๋‘˜๊ฒŒ์—ฌ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ๋ด์ฃผ์„ธ์—ฌ~

room-test์—์„œ ์ง€์›ํ•˜๋Š” MigrationTestHelper ๊ฐ€ scheme history๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ, androidTest/schemas/../pokeRogueDatabase/(dbVersion).json ์— ์ด์ „ ๋””๋น„ ๋ฒ„์ „์˜ scheme ๋“ค์ด ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ , ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ…Œ์ŠคํŠธ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด 2๊ฐ€์ง€ ์ข…๋ฅ˜์˜ ํ…Œ์ŠคํŠธ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

1) ๋‹จ์ผ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ…Œ์ŠคํŠธ (๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ํ…Œ์ŠคํŠธ)

DB ๋ฒ„์ „์„ ์˜ฌ๋ ค๋„ ์ด์ „ ๋ฐ์ดํ„ฐ๊ฐ€ ์†์ƒ์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”์ง€๋ฅผ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค!

// from: db version 1
data class User(
   @PrimaryKey val id: String,
    val name: String,
)

// to: db version 2

data class User(
   @PrimaryKey val id: String,
    val name: String,
    @ColumnInfo(defaultValue = -1)    
    val age: Int,
)

์œ„์™€ ๊ฐ™์ด User ์— age ๋ผ๋Š” ์ƒˆ๋กœ์šด ์ปฌ๋Ÿผ์ด ์ถ”๊ฐ€๋˜์—ˆ์œผ๋ฉด 2๊ฐ€์ง€ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ฉ๋‹ˆ๋‹ค.

  1. ๊ธฐ์กด ๋ฐ์ดํ„ฐ๊ฐ€ ์†์ƒ๋˜์—ˆ๋Š”๊ฐ€?
  2. ์ƒˆ๋กœ์šด ์ปฌ๋Ÿผ์— default ๊ฐ’์ด ๋“ค์–ด๊ฐ€๋Š”๊ฐ€

2) ์ „์ฒด ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ…Œ์ŠคํŠธ

๊ฐ€์žฅ ์˜ค๋ž˜๋œ db ๋ฒ„์ „์ด 1์ด๊ณ , ๊ฐ€์žฅ ์ตœ์‹  db ๋ฒ„์ „์ด 10์ด๋ผ๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ
1 ์—์„œ 10์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋Š”๋ฐ ๋ฌธ์ œ๊ฐ€ ์—†๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ…Œ์ŠคํŠธ์ž…๋‹ˆ๋‹ค!

DB Migration ํ…Œ์ŠคํŠธ

๋””๋น„ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•œ ์ดํ•ด๋ฅผ ์œ„ํ•ด ๊ฐ„๋‹จํ•˜๊ฒŒ ์ž‘์„ฑํ•ด๋‘˜๊ฒŒ์—ฌ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ๋ด์ฃผ์„ธ์—ฌ~

room-test์—์„œ ์ง€์›ํ•˜๋Š” MigrationTestHelper ๊ฐ€ scheme history๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ, androidTest/schemas/../pokeRogueDatabase/(dbVersion).json ์— ์ด์ „ ๋””๋น„ ๋ฒ„์ „์˜ scheme ๋“ค์ด ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ , ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ…Œ์ŠคํŠธ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด 2๊ฐ€์ง€ ์ข…๋ฅ˜์˜ ํ…Œ์ŠคํŠธ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

1) ๋‹จ์ผ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ…Œ์ŠคํŠธ (๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ํ…Œ์ŠคํŠธ)

DB ๋ฒ„์ „์„ ์˜ฌ๋ ค๋„ ์ด์ „ ๋ฐ์ดํ„ฐ๊ฐ€ ์†์ƒ์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”์ง€๋ฅผ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค!

// from: db version 1
data class User(
   @PrimaryKey val id: String,
    val name: String,
)

// to: db version 2

data class User(
   @PrimaryKey val id: String,
    val name: String,
    @ColumnInfo(defaultValue = -1)    
    val age: Int,
)

์œ„์™€ ๊ฐ™์ด User ์— age ๋ผ๋Š” ์ƒˆ๋กœ์šด ์ปฌ๋Ÿผ์ด ์ถ”๊ฐ€๋˜์—ˆ์œผ๋ฉด 2๊ฐ€์ง€ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ฉ๋‹ˆ๋‹ค.

  1. ๊ธฐ์กด ๋ฐ์ดํ„ฐ๊ฐ€ ์†์ƒ๋˜์—ˆ๋Š”๊ฐ€?
  2. ์ƒˆ๋กœ์šด ์ปฌ๋Ÿผ์— default ๊ฐ’์ด ๋“ค์–ด๊ฐ€๋Š”๊ฐ€

2) ์ „์ฒด ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ…Œ์ŠคํŠธ

๊ฐ€์žฅ ์˜ค๋ž˜๋œ db ๋ฒ„์ „์ด 1์ด๊ณ , ๊ฐ€์žฅ ์ตœ์‹  db ๋ฒ„์ „์ด 10์ด๋ผ๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ
1 ์—์„œ 10์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋Š”๋ฐ ๋ฌธ์ œ๊ฐ€ ์—†๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ…Œ์ŠคํŠธ์ž…๋‹ˆ๋‹ค!

Clone this wiki locally