TDD, ν΄λ¦° μ½λ with Kotlin 6κΈ° λΈλμ νΌλλ°±
Step2
https://github.com/next-step/kotlin-blackjack/pull/528
Test Double
λ¨μ ν μ€νΈλ₯Ό μν΄ μμ‘΄μ± μ£Όμ λΆλΆμ ν μ€νΈ λλΈμ μ¬μ©ν΄ ν μ€νΈλ₯Ό μ’ λ νΈλ¦¬νκ² ν μ μλλ‘ κ΅¬ννμλ€. λ€λ§, νΌλλ°±μ λ°μΌλ©° Stub, Mock, Fake λ± ν μ€νΈ λλΈμ μ’ λ₯μ λν΄ λͺ νν μκ³ μ¬μ©νλκ² μ’μ κ² κ°μ μ 리ν΄λ³΄λ € νλ€.
- Dummy
- λμνμ§ μμλ ν μ€νΈμλ μν₯μ λ―ΈμΉμ§ μλ κ°μ²΄λ₯Ό Dummy κ°μ²΄λΌκ³ νλ€.
- λ¨μ μΈμ€ν΄μ€νν κ°μ²΄λ₯Ό μλ―Ένλ€.
- Stub
- ν μ€νΈμμ νΈμΆλ μμ²μ λν΄ λ―Έλ¦¬ μ€λΉν΄λ κ²°κ³Όλ₯Ό μ 곡νλ€.
- μ¦, ν μ€νΈλ₯Ό μν΄ λ―Έλ¦¬ λ§λ€μ΄λμ κ°μ²΄λ§μ λ°ννλ€. (κ°μ²΄μ μνλ₯Ό κ²μ¦ν λ μ£Όλ‘ μ¬μ©νλ€.)
- Mock
- νΈμΆμ λν κΈ°λλ₯Ό λͺ μΈνκ³ λ΄μ©μ λ°λΌ λμνλλ‘ νλ‘κ·Έλλ° λ κ°μ²΄μ΄λ€.
- μ€μ λ‘ ν¨μκ° μ νΈμΆλμλμ§ κ²μ¦νλλ° λ λͺ©μ μ΄ μκ³ (νλ κ²μ¦) ν μ€νΈ μλ κ°μ λ° κ²μ¦νκ³ μΆμ ν μ€νΈμ μ§μ€νκ³ μΆμ λ κ²μ¦νκ³ μ νλ κ²μ μ μΈν λ€λ₯Έ κ°μ²΄λ€μ λͺ¨νΉνμ¬ μ¬μ©νλ€.
- Fake
- 볡μ‘ν λ‘μ§μ κ°μ§ ν¨μμ λμμ λ¨μννμ¬ κ΅¬νν κ°μ²΄μ΄λ€.
- μ¦, λμμ νμ§λ§ μ€μ μ¬μ©λλ κ°μ²΄μ²λΌ μ κ΅νκ² λμνμ§λ μλ κ°μ²΄λ₯Ό λ§νλ€.
- μλ₯Ό λ€λ©΄, InMemoryRepositoryμ κ°μ΄ ν μ€νΈλ₯Ό μν΄ κ°μ§ λ°μ΄ν°λ² μ΄μ€λ₯Ό λ§λλ κ²κ³Ό κ°μ μμκ° μλ€. μ κ΅νμ§λ μμ§λ§ μ€μ λ°μ΄ν°λ² μ΄μ€μ λμΌν μν μ νλ€.
μ°Έκ³
https://tecoble.techcourse.co.kr/post/2020-09-19-what-is-test-double/
Lazy Property μ¬μ©
λΆλ³ κ°μ²΄λΌλ©΄ μ κ·Όν λλ§λ€ λ‘μ§μ μ€ννμ§ μκ³ μ²μ μ κ·Όνμ λ νλ²λ§ μ€ννκ³ μ΄κΈ°ννλ λ°©λ²μ μ¬μ©ν μ μλ€.
μ΄λ κ² μ¬μ©ν κ²½μ° μ€λ³΅λλ κ³μ°μ νΌν΄ λ©λͺ¨λ¦¬ μ μ½μ ν μ μλ€.
val lazyValue: String by lazy {
println("computed!") // μ²μ μ κ·Όν λ λ± νλ²λ§ μ€ν
"Hello"
}
// println(lazyValue)
// println(lazyValue)
// -- μΆλ ₯ --
computed!
Hello
Hello
μ°Έκ³
https://kotlinlang.org/docs/delegated-properties.html#lazy-properties
λΉλμ μ‘°μ μ
λ©μλ λ€μ΄λ°μ λν 리뷰λ₯Ό λ°μλ€. μ¬μ€ λ©μλλͺ μ μ΅λν κ°λ μ±μκ² μμ±νλ €κ³ λ Έλ ₯νμ§λ§ λ°ν νμ μ λν΄μλ μ μ€νκ² μκ°νμ§ μμλ κ² κ°λ€.
μλ κ°νΈ μ€λΈμ νΈ μ± λ΄μ© μ€ μ’μ λ©μλ λ€μ΄λ°μ νλ λ°©λ²μ΄ μ μλμ΄ μλ€.
λΉλμ μ‘°μ μ μ λν λ΄μ©μ΄μλλ°
- λΉλ
- λΉλλ λκ°λ₯Ό λ§λ€κ³ μλ‘μ΄ κ°μ²΄λ₯Ό λ°ννλ λ©μλλ₯Ό λ§νλ€. λ°ν νμ μ μ λ voidκ° λ μ μμΌλ©° λͺ μ¬, νμ©μ¬λ‘ νννλ€.
fun pow(base: Int, power: Int): Int
fun employee(id: Int): Employee
fun parsedCell(x: Int, y: Int): String
fun bytedSaved(content: String): Int
- μ‘°μ μ
- μ‘°μ μλ κ°μ²΄λ‘ μΆμνν μν°ν°λ₯Ό μμ νλ λ©μλλ₯Ό λ§νλ€. λ°ν νμ μ νμ voidμ΄λ©° μ΄λ¦μ νμ λμ¬μ΄λ€.
- μ‘°μ μμ κ²½μ° μλ―Έλ₯Ό μ’ λ νλΆνκ² μ€λͺ νκΈ° μν΄μ λΆμ¬ νμ©μ΄ κ°λ₯νλ€.
fun save(content: String)
fun put(key: String, value: Float)
fun remote(emp: Employee)
fun quicklyPrint(id: Int)
- κ°μ²΄μ§ν₯μ μΈ μ κ·Όλ²μΌλ‘ λ©μλλͺ
μ μ μ§μΌλ €λ©΄ μ΄λ€ κ²μ λ°ννλ λ©μλ μ΄λ¦μ λμ¬λ‘ μ§κΈ° 보λ€λ λͺ
μ¬λ‘ μ§κ³ (λΉλ) 무μΈκ°λ₯Ό λ³κ²½ν λμλ λμ¬(μ‘°μ μ)λ₯Ό μ¬μ©νμ
- λ©μλ λͺ
μ μλͺ
νκΈ° μ΄λ ΅λ€λ©΄ κ·Έ λ©μλμμ λͺ©ννλ μμ
μ΄ νλκ° μλ κ°λ₯μ±μ΄ λλ€.
- Boolean κ°μ λ°ννλ λΉλλ μμΈ. μ΄ κ²½μ°μ νμ©μ¬
μ°Έκ³
https://lovethefeel.tistory.com/163?category=1002227
https://jessyt.tistory.com/141
Functional Interface
μΆμ λ©μλκ° νλλ§ μλ μΈν°νμ΄μ€μ λν΄ functional interface λ₯Ό μ μ©ν μ μλ€.
fun interface CardGenerator {
fun generate(): Card
}
val randomCardGenerator = CardGenerator {
Card(Rank.random(), Suit.random())
}
μμ κ°μ΄ functional interface λ₯Ό μ μ©νλ©΄ κ°κ²°ν ν¨μν μ½λ μμ±μ΄ κ°λ₯ν΄μ§λ©° 짧μ λλ€ ννμμΌλ‘ λΆνμν μ½λλ₯Ό μ€μΌ μ μλ€.
μ°Έκ³
• https://kotlinlang.org/docs/fun-interfaces.html
Step3
https://github.com/next-step/kotlin-blackjack/pull/554
μΌκΈ 컬λ μ κ³Ό λΆλ³ κ°μ²΄
μΌκΈ 컬λ μ μ λ§λ€μλ€κ³ ν΄μ λ°λμ λ΄λΆκ° λΆλ³ κ°μ²΄μΌ νμλ μλ€. νμ§λ§ νλμ νλ‘νΌν°λ₯Ό κ°μ§κΈ° λλ¬Έμ λΆλ³κ°μ²΄λ‘ λ§λ€μμ λμ μ₯μ μ΄ λλ ·ν΄ μλμ κ°μ΄ λΆλ³ κ°μ²΄λ‘ ν¨κ» κ°μ Έκ°λ κ²μ΄ μ’λ€.
data class Cards(
val values: List<Card> = emptyList()
) {
constructor(vararg card: Card) : this(values = card.toList())
val sumOfScoreWithAceAsOne: Int by lazy {
values.sumOf { it.getScore() }
}
val numberOfAce: Int by lazy {
values.count { it.rank == Rank.ACE }
}
}
리뷰μ΄λμ λΆλ³κ°μ²΄λ‘ λ§λλ κ² μ체λ μ’μ μλμ΄μ§λ§ νμ€ μΈκ³μ κ΄μ μμ 보μμ λ νλ μ΄μ΄λ λλ¬κ° λ€κ³ μλ μΉ΄λ λλ―Έ λν λ³ν μ μμ΄ λ¬΄λ¦¬νκ² λΆλ³μΌλ‘ λ§λ€ νμλ μμ΄λ³΄μΈλ€λ μ견μ λ§μν΄μ£Όμ ¨λ€.
νμ€μμ νλ μ΄μ΄λ λλ¬κ° λ€κ³ μλ μΉ΄λ λλ―Έκ° λ³ν μ μλ μꡬμ¬νμ΄κΈ° λλ¬Έμ 무리νκ² λΆλ³μΌλ‘ λ§λ€μ§λ μμλ λ κ² κ°λ€λ μ견μ 곡κ°νκ³ λΆλ³κ°μ²΄λ₯Ό μ°μ μ μΌλ‘ μκ°νλ, μ μ°νκ² κ°λ³κ°μ²΄μ κ΄μ μμ μκ°ν΄λ³΄λ κ²λ μ’μ κ² κ°λ€.
Step4
https://github.com/next-step/kotlin-blackjack/pull/568
컬λ μ μ λ³κ²½μ§μ
class Cards(
values: List<Card> = emptyList(),
) {
var values: List<Card> = values
private set
constructor(vararg card: Card) : this(values = card.toMutableList())
val sumOfScoreWithAceAsOne: Int
get() = values.sumOf { it.getScore() }
val numberOfAce: Int
get() = values.count { it.rank == Rank.ACE }
fun add(card: Card) {
values = values + card
}
fun addAll(cards: List<Card>) {
values = values + cards
}
}
Cards ν΄λμ€λ₯Ό κ°λ³νκ² λ³κ²½νλ©΄μ mutableList λ₯Ό λ§λ€κ³ λ°©μ΄μ 볡μ¬λ‘ λ°νν μ§, λλ var (private set) λ‘ νλ‘νΌν° μ체λ₯Ό λ³κ²½ μ§μ μΌλ‘ λκ³ addλ₯Ό ν λλ§λ€ μλ‘μ΄ λ¦¬μ€νΈλ₯Ό λ§λ€μ§ κ³ λ―Όμ νλ€.
리뷰μ΄λλ μ΄ λΆλΆμ λν΄ λ¦¬λ·°λ₯Ό ν΄μ£Όμ ¨κ³ valuesλ MutableListλ‘ λκ³ , μΈλΆμ Listλ₯Ό λ°ννλ getterλ₯Ό λ ΈμΆμν¨ νμ μ κ·Όν λ valuesλ₯Ό 볡μ (copy)ν Listλ₯Ό λ§λ€μ΄μ λ°νν΄λ μ’μ κ² κ°λ€λ μ견μ μ£Όμ ¨λ€.
var λ₯Ό ν΅ν΄ νλ‘νΌν° μ체λ₯Ό λ³κ²½ μ§μ μΌλ‘ λμμ λκ° mutableList λ‘ λ¦¬μ€νΈ λ΄λΆμ λ³κ²½μ§μ μ λλ κ²λ³΄λ€ λ©ν° μ€λ λ νκ²½μμ μμ μ±μ΄ ν¬κΈ° λλ¬Έμ νλ‘νΌν° μ체λ₯Ό λ³κ²½ μ§μ μΌλ‘ λλ λ°©μμ μ ννλ€.
λ€λ§ νμ¬ λ―Έμ μμ μ€λ λ μμ μ±μ κ³ λ €ν΄μΌν μν©μ μλκΈ° λλ¬Έμ μλκ° λ λΉ λ₯Έ mutableListλ₯Ό μ¬μ©νκ³ λ°©μ΄μ 볡μ¬λ‘ 리ν΄νλ κ²λ μ’μ λ°©λ²μΈ κ² κ°λ€.