Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Step4 #1003

Open
wants to merge 8 commits into
base: gongwho
Choose a base branch
from
41 changes: 34 additions & 7 deletions src/main/kotlin/lotto/LottoSimulator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ package lotto
import lotto.domain.LottoPurchaseOrder
import lotto.domain.LottoResult
import lotto.domain.LottoTicket
import lotto.provider.ticket.AutoTicketProvider
import lotto.provider.ticket.LottoTicketsProvider
import lotto.domain.LottoTickets
import lotto.domain.RankResult
import lotto.generator.ActualLottoShop
import lotto.generator.LottoShop
import lotto.generator.ticket.AutoTicketGenerator
import lotto.generator.ticket.ManualTicketGenerator
import lotto.view.InputView
import lotto.view.ResultView
import lotto.view.UserInputView
Expand All @@ -13,16 +17,16 @@ class LottoSimulator(
private val inputView: InputView,
private val resultView: ResultView,
) {
fun simulate(lottoTicketsProvider: LottoTicketsProvider): LottoResult {
fun simulate(lottoShop: LottoShop): LottoResult {
val purchaseOrder = LottoPurchaseOrder(
budget = inputView.getBudget(),
ticketPrice = LottoTicket.PRICE,
)

val lottoTickets = lottoTicketsProvider.provide(purchaseOrder.ticketCount)
inputView.printPurchasedLotto(lottoTickets)
val lottoTickets = generateLottoTickets(lottoShop, purchaseOrder.ticketCount)

val winningNumber = inputView.getWinningNumber()

val lottoResult = lottoTickets.getRankResult(winningNumber)

val result = LottoResult(
Expand All @@ -31,15 +35,38 @@ class LottoSimulator(
remainder = purchaseOrder.remainder
)

printLottoResult(lottoResult, result)

return result
}

private fun printLottoResult(lottoResult: RankResult, result: LottoResult) {
resultView.printRankResults(lottoResult)
resultView.printResult(result)
return result
}

private fun generateLottoTickets(lottoShop: LottoShop, ticketCount: Int): LottoTickets {
val manualLottoCount = inputView.getManualLottoCount()

val manualTickets = if (manualLottoCount != 0) {
lottoShop.provideManualTickets(inputView.getManualNumbers(manualLottoCount))
} else LottoTickets(listOf())

val autoTickets = lottoShop.provideAutoTickets(ticketCount, manualLottoCount)
inputView.printPurchasedLotto(autoLottoTickets = autoTickets, manualLottoTickets = manualTickets)
Comment on lines +51 to +56

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

자동로또와 수동로또를 구매하는 역할도 LottoShop이 가지고 있어도 좋을거 같다는 생각이들어요!
단순히 provide해주는 객체가 아닌, manualNumbers와 budget 정보만으로 로또를 생성해줄수 있지않을까요?

LottoSimulator는 Controller역할로 View와의 상호작용에 대한 책임만 있지, 어떤 로또가 provide등의 책임은 LottoShop에게 모두 위임해보아요!


return LottoTickets(manualTickets.lottoTicketList + autoTickets.lottoTicketList)
}
}

fun main() {
LottoSimulator(
UserInputView(),
ResultView()
).simulate(lottoTicketsProvider = AutoTicketProvider)
).simulate(
lottoShop = ActualLottoShop(
autoTicketGenerator = AutoTicketGenerator,
manualTicketGenerator = ManualTicketGenerator,
)
)
}
7 changes: 0 additions & 7 deletions src/main/kotlin/lotto/domain/ManualTicketProvideStrategy.kt

This file was deleted.

14 changes: 14 additions & 0 deletions src/main/kotlin/lotto/generator/ActualLottoShop.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package lotto.generator

import lotto.domain.LottoTickets
import lotto.generator.ticket.AutoTicketGenerator
import lotto.generator.ticket.ManualTicketGenerator

class ActualLottoShop(
private val autoTicketGenerator: AutoTicketGenerator,
private val manualTicketGenerator: ManualTicketGenerator,
Comment on lines +8 to +9

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AutoTicketGenerator, ManualTicketGenerator
추상화를 제거하고, 하나의 object 클래스로 만들어주셨군요
TicketGenerator라는 추상화를 해보면 어떨까요?

ActualLottoShop 관련해서 Fake객체를 주입시켜, 구체적인 테스트도 작성할수 있을거같아요

) : LottoShop {
override fun provideAutoTickets(ticketCount: Int, preGeneratedTicketCount: Int): LottoTickets = autoTicketGenerator.create(ticketCount - preGeneratedTicketCount)
override fun provideManualTickets(manualNumbersList: List<List<Int>>): LottoTickets =
manualTicketGenerator.create(manualNumbersList)
}
8 changes: 8 additions & 0 deletions src/main/kotlin/lotto/generator/LottoShop.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package lotto.generator

import lotto.domain.LottoTickets

interface LottoShop {
fun provideAutoTickets(ticketCount: Int, preGeneratedTicketCount: Int): LottoTickets
fun provideManualTickets(manualNumbersList: List<List<Int>>): LottoTickets

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

List<List>가 어떤데이터인지 알기힘들진 않을까요?

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package lotto.domain
package lotto.generator.ticket

import lotto.provider.ticket.TicketProvideStrategy
import lotto.domain.LottoNumber
import lotto.domain.LottoTicket
import lotto.domain.LottoTickets

object AutoTicketProvideStrategy : TicketProvideStrategy {
object AutoTicketGenerator {
private val preGeneratedLottoNumbers = (LottoNumber.validNumberRange)
.map { LottoNumber(it) }
override fun provide(ticketCount: Int): LottoTickets {

fun create(ticketCount: Int): LottoTickets {
val tickets = List(ticketCount) {
LottoTicket(
preGeneratedLottoNumbers
Expand Down
15 changes: 15 additions & 0 deletions src/main/kotlin/lotto/generator/ticket/ManualTicketGenerator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package lotto.generator.ticket

import lotto.domain.LottoNumber
import lotto.domain.LottoTicket
import lotto.domain.LottoTickets

object ManualTicketGenerator {
fun create(manualNumbersList: List<List<Int>>): LottoTickets {
return LottoTickets(
manualNumbersList.map { list ->
LottoTicket(list.map { LottoNumber(it) })
}
)
}
}
8 changes: 0 additions & 8 deletions src/main/kotlin/lotto/provider/ticket/AutoTicketProvider.kt

This file was deleted.

11 changes: 0 additions & 11 deletions src/main/kotlin/lotto/provider/ticket/LottoTicketsProvider.kt

This file was deleted.

6 changes: 5 additions & 1 deletion src/main/kotlin/lotto/view/InputView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,9 @@ interface InputView {

fun getWinningNumber(): WinningNumber

fun printPurchasedLotto(lottoTickets: LottoTickets)
fun printPurchasedLotto(autoLottoTickets: LottoTickets, manualLottoTickets: LottoTickets)

fun getManualLottoCount(): Int

fun getManualNumbers(manualLottoCount: Int): List<List<Int>>
}
27 changes: 24 additions & 3 deletions src/main/kotlin/lotto/view/UserInputView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,35 @@ class UserInputView : InputView {
)
}

override fun printPurchasedLotto(lottoTickets: LottoTickets) {
lottoTickets.lottoTicketList.forEach { ticket ->
override fun printPurchasedLotto(autoLottoTickets: LottoTickets, manualLottoTickets: LottoTickets) {
println("수동으로 ${manualLottoTickets.lottoTicketList.size}, 자동으로 ${autoLottoTickets.lottoTicketList.size} 개를 구매했습니다.")
manualLottoTickets.print()
autoLottoTickets.print()
}

override fun getManualLottoCount(): Int {
println("수동으로 구매할 로또 수를 입력해 주세요.")
return readln().trim().toInt()
}

override fun getManualNumbers(manualLottoCount: Int): List<List<Int>> {
println("수동으로 구매할 번호를 입력해 주세요.")
val lottoTicketNumbers = mutableListOf<List<Int>>()

repeat(manualLottoCount) {
val lottoTicket = readln().trim().split(",").map { it.toInt() }
lottoTicketNumbers.add(lottoTicket)
}
return lottoTicketNumbers
}

private fun LottoTickets.print() {
lottoTicketList.forEach { ticket ->
println(
ticket.lottoNumberList.map { number ->
number.value
}
)
}
println("${lottoTickets.lottoTicketList.size} 개를 구매했습니다.")
}
}
46 changes: 15 additions & 31 deletions src/test/kotlin/lotto/LottoAutoTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
import lotto.domain.LottoNumber
import lotto.domain.LottoTicket
import lotto.domain.LottoTickets
import lotto.domain.ManualTicketProvideStrategy
import lotto.domain.Rank
import lotto.domain.WinningNumber
import lotto.provider.ticket.MockTicketProvider
import lotto.generator.MockLottoShop
import lotto.generator.ticket.ManualTicketGenerator
import lotto.view.MockInputView
import lotto.view.ResultView

Expand All @@ -17,68 +16,53 @@ class LottoAutoTest : StringSpec({
"winning statistics should calculate correct profit" {
LottoSimulator(
inputView = MockInputView(
budget = 5000,
budget = 1000,
winningNumber = WinningNumber(
LottoTicket(listOf(1, 2, 3, 4, 5, 6).map { LottoNumber(it) }),
bonusNumber = LottoNumber(19)
),
manualNumbersList = listOf(listOf(1, 2, 3, 4, 5, 6))
),
resultView = ResultView(),
).simulate(
lottoTicketsProvider = MockTicketProvider(
ManualTicketProvideStrategy(
LottoTickets(
listOf(
LottoTicket(listOf(1, 2, 3, 4, 5, 6).map { LottoNumber(it) })
)
)
),
lottoShop = MockLottoShop(
manualTicketGenerator = ManualTicketGenerator
)
).totalPrize shouldBe Rank.FirstPlace.prize
}

"winning statistics should show correct ROI" {
LottoSimulator(
inputView = MockInputView(
budget = 5000,
budget = 1000,
winningNumber = WinningNumber(
LottoTicket(listOf(1, 2, 3, 4, 5, 6).map { LottoNumber(it) }),
bonusNumber = LottoNumber(19)
),
manualNumbersList = listOf(listOf(1, 2, 3, 4, 5, 6))
),
resultView = ResultView(),
).simulate(
lottoTicketsProvider = MockTicketProvider(
ManualTicketProvideStrategy(
LottoTickets(
listOf(
LottoTicket(listOf(1, 2, 3, 4, 5, 6).map { LottoNumber(it) })
)
)
)
lottoShop = MockLottoShop(
manualTicketGenerator = ManualTicketGenerator
),
).profitRate.shouldBe(400_000)
).profitRate.shouldBe(2_000_000)
}

"second place result should be correct" {
LottoSimulator(
inputView = MockInputView(
budget = 5000,
budget = 1000,
winningNumber = WinningNumber(
LottoTicket(listOf(1, 2, 3, 4, 5, 9).map { LottoNumber(it) }),
bonusNumber = LottoNumber(19)
),
manualNumbersList = listOf(listOf(1, 2, 3, 4, 5, 19))
),
resultView = ResultView(),
).simulate(
lottoTicketsProvider = MockTicketProvider(
ManualTicketProvideStrategy(
LottoTickets(
listOf(
LottoTicket(listOf(1, 2, 3, 4, 5, 19).map { LottoNumber(it) })
)
)
)
lottoShop = MockLottoShop(
manualTicketGenerator = ManualTicketGenerator
),
).totalPrize shouldBe Rank.SecondPlace.prize
}
Expand Down
10 changes: 10 additions & 0 deletions src/test/kotlin/lotto/generator/MockLottoShop.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package lotto.generator

import lotto.domain.LottoTickets
import lotto.generator.ticket.ManualTicketGenerator

class MockLottoShop(private val manualTicketGenerator: ManualTicketGenerator) : LottoShop {
override fun provideAutoTickets(ticketCount: Int, preGeneratedTicketCount: Int): LottoTickets = LottoTickets(listOf())
override fun provideManualTickets(manualNumbersList: List<List<Int>>): LottoTickets =
manualTicketGenerator.create(manualNumbersList)
Comment on lines +6 to +9

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 Mock객체는 정상적인 동작을 한다고 보기는 힘들지 않을까요?
fake객체라면 원하는대로 활용할수있는구조로 작성해봐도 좋을거같아요

추상화를 한 이유와 Fake객체를 사용하는 이유가 무엇일지 고민해보면 어떨까요?
테스트가능한 구조를 구민보아요

Suggested change
class MockLottoShop(private val manualTicketGenerator: ManualTicketGenerator) : LottoShop {
override fun provideAutoTickets(ticketCount: Int, preGeneratedTicketCount: Int): LottoTickets = LottoTickets(listOf())
override fun provideManualTickets(manualNumbersList: List<List<Int>>): LottoTickets =
manualTicketGenerator.create(manualNumbersList)
class MockLottoShop(
private val autoTickets: LottoTickets,
private val manualTicket: LottoTickets,
) : LottoShop {
override fun provideAutoTickets(ticketCount: Int, preGeneratedTicketCount: Int): LottoTickets = autoTickets
override fun provideManualTickets(manualNumbersList: List<List<Int>>): LottoTickets = manualTicket

}
14 changes: 14 additions & 0 deletions src/test/kotlin/lotto/generator/ticket/AutoTicketGeneratorTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package lotto.generator.ticket

import io.kotest.core.spec.style.BehaviorSpec
import io.kotest.matchers.shouldBe

class AutoTicketGeneratorTest : BehaviorSpec({
given("auto ticket generator") {
`when`("creates lotto Tickets") {
then("should provide correct ticket count") {
AutoTicketGenerator.create(3).lottoTicketList.size shouldBe 3
}
}
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package lotto.generator.ticket

import io.kotest.core.spec.style.BehaviorSpec
import io.kotest.matchers.shouldBe
import lotto.domain.LottoNumber
import lotto.domain.LottoTicket

class ManualTicketGeneratorTest : BehaviorSpec({
given("manual ticket generator") {
`when`("creates lotto Tickets") {
then("should provide correct tickets") {
val ticketBlueprint1 = listOf(1, 2, 3, 4, 5, 6)
val ticketBlueprint2 = listOf(3, 4, 5, 6, 7, 8)
val ticketBlueprint3 = listOf(5, 6, 7, 8, 9, 13)

val lottoTickets = ManualTicketGenerator.create(
listOf(
ticketBlueprint1,
ticketBlueprint2,
ticketBlueprint3,
)
)
lottoTickets.lottoTicketList.size shouldBe 3
lottoTickets.lottoTicketList[0] shouldBe LottoTicket(ticketBlueprint1.map { LottoNumber(it) })
lottoTickets.lottoTicketList[1] shouldBe LottoTicket(ticketBlueprint2.map { LottoNumber(it) })
lottoTickets.lottoTicketList[2] shouldBe LottoTicket(ticketBlueprint3.map { LottoNumber(it) })
gongwho marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
})
8 changes: 0 additions & 8 deletions src/test/kotlin/lotto/provider/ticket/MockTicketProvider.kt

This file was deleted.

7 changes: 6 additions & 1 deletion src/test/kotlin/lotto/view/MockInputView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@ import lotto.domain.WinningNumber
class MockInputView(
private val budget: Int,
private val winningNumber: WinningNumber,
private val manualNumbersList: List<List<Int>>,
) : InputView {
override fun getBudget(): Int = budget

override fun getWinningNumber(): WinningNumber = winningNumber

override fun printPurchasedLotto(lottoTickets: LottoTickets) = Unit
override fun printPurchasedLotto(autoLottoTickets: LottoTickets, manualLottoTickets: LottoTickets) = Unit

override fun getManualLottoCount(): Int = manualNumbersList.size

override fun getManualNumbers(manualLottoCount: Int): List<List<Int>> = manualNumbersList
}