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

Step1 미션 제출합니다 #20

Open
wants to merge 8 commits into
base: briandr97
Choose a base branch
from
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,23 @@
휴 이제야 됐네요!
# 기능
- 로또 티켓 자동 발급 가능
- 로또 티켓 수동 발급 가능 (공백으로 구분한 6개의 숫자)
- 당첨 번호 직접 설정 가능 (공백으로 구분한 7개의 숫자)
- 당첨 번호와 티켓 비교 후 결과 출력

# Money 클래스 테스트
- [x] 돈이 음수가 될 수 없다
- [x] plus가 제대로 작동하는지 테스트
- [x] minus가 제대로 작동하는지 테스트

# LottoNumber 클래스 테스트
- [x] 입력된 숫자가 1~45 사이여야한다 (기본 생성자 테스트)
- [x] of 함수가 제대로 작동하는지 테스트

# LottoTicket 클래스 테스트
- [x] 로또 번호가 여섯개여야한다
- [x] 기본 생성자로 테스트
- [x] vararg numbers: Int를 넘겼을 때 잘 생성되는지 테스트
- [x] numbers: List<LottoNumber>를 넘겼을 때 잘 생성되는지 테스트
- [ ] has 함수가 제대로 작동하는지 테스트
- [x] countMatchingNumbers 함수가 제대로 작동하는지 테스트
- [x] toString 함수가 제대로 작동하는지 테스트
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.malibin.study.domain.lotto

@JvmInline
value class LottoNumber private constructor(
val number: Int,
val number: Int
) {
Comment on lines +5 to 6
Copy link
Member

Choose a reason for hiding this comment

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

요기 tailing comma는 지우신 이유가 있을까요 ?_?

init {
require(number in RANGE) { "입력 숫자 ($number)는 로또 숫자 범위(1 ~ 45) 내의 숫자가 아닙니다." }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.malibin.study.domain.lotto.cal

class AverageCalculator {
fun calculateAverage(numbers: List<Int>): Int {
return numbers.sum() / numbers.size
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.malibin.study.domain.lotto.ticket
import com.malibin.study.domain.lotto.LottoNumber

data class LottoTicket(
val lottoNumbers: Set<LottoNumber>,
val lottoNumbers: Set<LottoNumber>
) {
init {
require(lottoNumbers.size == LOTTO_NUMBERS_AMOUNT) { "로또 티켓에 번호는 6개만 넣을 수 있습니다. 입력 값 : $lottoNumbers" }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.malibin.study.domain.lotto

import com.google.common.truth.Truth.assertThat
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource

class LottoNumberTest {

@ValueSource(ints = [0, 46])
@ParameterizedTest
fun `1~45가 아닐 때 에러가 발생하는지에 대한 테스트`(number: Int) {
// when
val exception = kotlin.runCatching { LottoNumber.of(number) }.exceptionOrNull()

// then
assertThat(exception).isInstanceOf(Exception::class.java)
assertThat(exception).hasMessageThat().contains("돈의 액수는 음수가 될 수 없습니다. 입력 값 : $number")
Comment on lines +15 to +17
Copy link
Member

Choose a reason for hiding this comment

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

assertAll 로 감싸는 것과 그렇지 않은 것의 차이점은 무엇일까요?

}

@ValueSource(ints = [1, 2, 3])
@ParameterizedTest
fun `of 함수 테스트`(number: Int) {
// when
val lottoNumber = LottoNumber.of(number)

// then
assertThat(lottoNumber.number).isEqualTo(number)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.malibin.study.domain.lotto.cal

import com.google.common.truth.Truth.assertThat
import com.malibin.study.domain.lotto.ticket.LottoTicket
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.CsvSource
import org.junit.jupiter.params.provider.MethodSource
import org.junit.jupiter.params.provider.ValueSource

internal class AverageCalculatorTest {
@Test
fun `평균을 구할 수 있다`() {
// given
val integers = listOf<Int>(1, 2, 3, 4, 5)
val averageCalculator = AverageCalculator()

// when
val actualAverage = averageCalculator.calculateAverage(integers)

// then
assertThat(actualAverage).isEqualTo(3)
}

@ValueSource(strings = ["Heart", "Diamond", "Clover", "Spade"])
@ParameterizedTest
fun `value에 맞는 올바른 Suit를 찾을 수 있다`(suitValue: String) {
// given

// when
val actualSuit = Suit.find(suitValue)

// then
assertThat(actualSuit.value).isEqualTo(suitValue)
}

@CsvSource(value = ["Heart,HEART", "Diamond,DIAMOND", "Clover,CLOVER", "Spade,SPADE"])
@ParameterizedTest
fun `Enum클래스로 직접 비교하여 value에 맞는 올바른 Suit를 찾을 수 있다`(suitValue: String, expectedSuit: Suit) {
// given

// when
val actualSuit = Suit.find(suitValue)

// then
assertThat(actualSuit).isEqualTo(expectedSuit)
}

@MethodSource("providesLottoTickets")
@ParameterizedTest
fun `좀 더 어려운 인자를 넣어주는 테스트`() {
// given
val ticket = LottoTicket(1, 2, 3, 4, 5, 6)

// when

// then
}

companion object {
// 여러 자료형들을 아래처럼 인자로 넘길 수 있다!!
// 위의 MethodSource를 이용해서 넣어준다~!
// 하지만 가독성이 최악이니 최후의 수단이라고 생각하자
fun providesLottoTickets(): List<Arguments> = listOf(
Arguments.of(LottoTicket(1, 2, 3, 4, 5, 6), 1, ""),
Arguments.of(LottoTicket(1, 2, 3, 4, 5, 6), 1, ""),
Arguments.of(LottoTicket(1, 2, 3, 4, 5, 6), 1, "")
)
}

enum class Suit(val id: Int, val value: String) {
HEART(0, "Heart"),
DIAMOND(1, "Diamond"),
CLOVER(2, "Clover"),
SPADE(3, "Spade");

companion object {
fun find(value: String): Suit = values().first() { it.value == value }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.malibin.study.domain.lotto.result

import com.google.common.truth.Truth.assertThat
import org.junit.jupiter.api.Test

class MoneyTest {
@Test
fun `양수만 받는지 테스트`() {
Comment on lines +7 to +8
Copy link
Member

Choose a reason for hiding this comment

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

테스트명이 더 구체적이었으면 좋겠어요 :)

// when
val exception = kotlin.runCatching { Money(-1) }.exceptionOrNull()

// given
assertThat(exception).isInstanceOf(Exception::class.java)
Comment on lines +12 to +13
Copy link
Member

Choose a reason for hiding this comment

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

Exception은 Throwable 하위의 Exception 최상위 객체예요.
더 구체적인 Exception instance를 비교해보는 것은 어떨까요?

assertThat(exception).hasMessageThat().contains("돈의 액수는 음수가 될 수 없습니다. 입력 값 : -1")
}

@Test
fun `plus 함수가 제대로 작동하는지 테스트`() {
// given
val money1 = Money(1)
val money2 = Money(2)
val money3 = Money(3)

// when
val resultMoney = money1 + money2

// then
assertThat(resultMoney.amount).isEqualTo(money3.amount)
}
Comment on lines +27 to +29
Copy link
Member

Choose a reason for hiding this comment

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

amount를 꺼내 비교하기보다, money객체 자체를 비교해보는 것은 어떨까요?


@Test
fun `minus 함수가 제대로 작동하는지 테스트`() {
// given
val money1 = Money(1)
val money2 = Money(2)
val money3 = Money(3)

// when
val resultMoney = money3 - money2

// then
assertThat(resultMoney.amount).isEqualTo(money1.amount)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package com.malibin.study.domain.lotto.ticket

import com.google.common.truth.Truth.assertThat
import com.malibin.study.domain.lotto.LottoNumber
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.MethodSource

internal class LottoTicketTest {
@Test
fun `로또 번호가 여섯개가 아닐 때 에러 메시지 확인 - 기본 생성자`() {
// given
val lottoNumbers = setOf<LottoNumber>(LottoNumber.of(1), LottoNumber.of(2))
val errorMessage: String = "로또 티켓에 번호는 6개만 넣을 수 있습니다. 입력 값 : [1, 2]"

Comment on lines +15 to +16
Copy link
Member

Choose a reason for hiding this comment

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

에러 메시지는 인라인으로 넣어줘도 괜찮아보여요 :)

// when
// val e: IllegalArgumentException = assertThrows { LottoTicket(lottoNumbers) }
val exception = kotlin.runCatching { LottoTicket(lottoNumbers) }.exceptionOrNull()

// then
assertThat(exception).hasMessageThat().contains(errorMessage)
assertThat(exception).isInstanceOf(Exception::class.java)
}

@Test
fun `로또 번호가 여섯 개일 때 잘 생성되는지 확인 - 기본 생성자`() {
// given
val lottoNumbers = setOf<LottoNumber>(
Comment on lines +26 to +29
Copy link
Member

Choose a reason for hiding this comment

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

잘 생성되는지 까지는 테스트하지 않아도 괜찮아 보여요 :)

LottoNumber.of(1),
LottoNumber.of(2),
LottoNumber.of(3),
LottoNumber.of(4),
LottoNumber.of(5),
LottoNumber.of(6)
)

// when
val lottoTicket = LottoTicket(lottoNumbers)

// then
assertThat(lottoTicket).isInstanceOf(LottoTicket::class.java)
}

@Test
fun `로또 번호가 여섯개가 아닐 때 에러 메시지 확인 - 보조 생성자1`() {
// given
val n1 = 1
val n2 = 2
val n3 = 3
val n4 = 4
val errorMessage: String = "로또 티켓에 번호는 6개만 넣을 수 있습니다. 입력 값 : [1, 2, 3, 4]"

// when
val exception = kotlin.runCatching { LottoTicket(n1, n2, n3, n4) }.exceptionOrNull()
Comment on lines +48 to +55
Copy link
Member

Choose a reason for hiding this comment

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

n1,n2.. 같은숫자들은 인라인으로 넣어도 충분해 보이네요 :)


// then
assertThat(exception).hasMessageThat().contains(errorMessage)
assertThat(exception).isInstanceOf(Exception::class.java)
}

@Test
fun `로또 번호가 여섯 개일 때 잘 생성되는지 확인 - 보조 생성자1`() {
// given
val n1 = 1
val n2 = 2
val n3 = 3
val n4 = 4
val n5 = 5
val n6 = 6

// when
val lottoTicket = LottoTicket(n1, n2, n3, n4, n5, n6)

// then
assertThat(lottoTicket).isInstanceOf(LottoTicket::class.java)
}

@Test
fun `로또 번호가 여섯개가 아닐 때 에러 메시지 확인 - 보조 생성자2`() {
Comment on lines +79 to +80
Copy link
Member

Choose a reason for hiding this comment

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

부생성자로 생성했을 때 다른 상태를 갖는 것이 아니라면,
코틀린의 모든 생성자는 최상위 생성자를 거치기 때문에, 보조 생성자에 대해 꼭 테스트하지 않아도 된다고 생각해요.

// given
val lottoNumbers = listOf<LottoNumber>(LottoNumber.of(1), LottoNumber.of(2))
val errorMessage: String = "로또 티켓에 번호는 6개만 넣을 수 있습니다. 입력 값 : [1, 2]"

// when
val exception = kotlin.runCatching { LottoTicket(lottoNumbers) }.exceptionOrNull()

// then
assertThat(exception).hasMessageThat().contains(errorMessage)
assertThat(exception).isInstanceOf(Exception::class.java)
}

@Test
fun `로또 번호가 여섯 개일 때 잘 생성되는지 확인 - 보조 생성자2`() {
// given
val lottoNumbers = listOf<LottoNumber>(
LottoNumber.of(1),
LottoNumber.of(2),
LottoNumber.of(3),
LottoNumber.of(4),
LottoNumber.of(5),
LottoNumber.of(6)
)

// when
val lottoTicket = LottoTicket(lottoNumbers)

// then
assertThat(lottoTicket).isInstanceOf(LottoTicket::class.java)
}

/*@MethodSource("providesLottoNumbers")
@ParameterizedTest
fun `has 함수 작동 테스트`(lottoValue: LottoNumber, expectedResult: Boolean) {
// given
val lottoNumbers = listOf<Int>(1, 2, 3, 4, 5, 6).map { LottoNumber.of(it) }
val lottoTicket = LottoTicket(lottoNumbers)

// when
val actualResult = lottoTicket.has(lottoValue)

// then
assertThat(actualResult).isEqualTo(expectedResult)
}*/

@MethodSource("providesLottoTickets")
@ParameterizedTest
fun `countMatchingNumbers 함수 작동 테스트`(otherLottoTickets: LottoTicket, expectedResult: Int) {
// given
val lottoNumbers = listOf<Int>(1, 2, 3, 4, 5, 6).map { LottoNumber.of(it) }
val lottoTicket = LottoTicket(lottoNumbers)

// when
val actualResult = lottoTicket.countMatchingNumbers(otherLottoTickets)

// then
assertThat(actualResult).isEqualTo(expectedResult)
}

@Test
fun `toString 함수 작동 테스트`() {
// given
val lottoNumbers = listOf<Int>(1, 2, 3, 4, 5, 6).map { LottoNumber.of(it) }
val lottoTicket = LottoTicket(lottoNumbers)
val expectedResult = "1, 2, 3, 4, 5, 6"

// when
val actualResult = lottoTicket.toString()

// then
assertThat(actualResult).isEqualTo(expectedResult)
}

companion object {
@JvmStatic
fun providesLottoNumbers(): List<Arguments> {
return listOf(
Arguments.of(LottoNumber.of(1), true),
Arguments.of(LottoNumber.of(2), true),
Arguments.of(LottoNumber.of(3), true),
Arguments.of(LottoNumber.of(4), true),
Arguments.of(LottoNumber.of(5), true),
Arguments.of(LottoNumber.of(6), true),
Arguments.of(LottoNumber.of(7), false)
)
}

@JvmStatic
fun providesLottoTickets(): List<Arguments> {
val lottoNumbers1 = listOf<Int>(1, 2, 3, 4, 5, 6).map { LottoNumber.of(it) }
val lottoNumbers2 = listOf<Int>(2, 3, 4, 5, 6, 7).map { LottoNumber.of(it) }
val lottoNumbers3 = listOf<Int>(3, 4, 5, 6, 7, 8).map { LottoNumber.of(it) }
val lottoNumbers4 = listOf<Int>(4, 5, 6, 7, 8, 9).map { LottoNumber.of(it) }

val lottoTicket1 = LottoTicket(lottoNumbers1)
val lottoTicket2 = LottoTicket(lottoNumbers2)
val lottoTicket3 = LottoTicket(lottoNumbers3)
val lottoTicket4 = LottoTicket(lottoNumbers4)

return listOf(
Arguments.of(lottoTicket1, 6),
Arguments.of(lottoTicket2, 5),
Arguments.of(lottoTicket3, 4),
Arguments.of(lottoTicket4, 3)
)
}
}
}