ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 코틀린(kotlin) - 숫자 야구 게임
    프로젝트/Kotlin + TDD 2022. 10. 22. 00:01
    728x90

    개요

    코틀린과 TDD에 친숙해지고자 자동차 경주 게임에 이어 숫자 야구 게임을 구현해 보겠습니다.

     

    요구 사항 정리

    1. 랜덤으로 1~9짜리 서로 다른 3개의 수를 생성한다.
    2. 사용자에게 수를 입력받는다.
    3. 입력받은 수를 검증한다.
    4. 입력받은 3자리 수에서 볼, 스트라이크 개수를 구해서 반환한다.
    5. 구해진 볼, 스트라이크를 통해 출력 값을 결정한다.
      • 스트라이크, 볼 0개 : "낫싱"
      • 스트라이크 0~2개, 볼 0개 아님 : "n볼 n스트라이크"
      • 스트라이크 3개 : "3 스트라이크"
        • 정답 문구 출력 : "3개의 숫자를 모두 맞히셨습니다! 게임 종료"
    6. 스트라이크 3개가 나올 때까지 2~5 과정을 반복한다.

     

    README.md

    ### 요구 사항
    - [ ] 랜덤으로 1~9까지의 숫자 3개 생성
    - [ ] 사용자에게 3자리 숫자를 입력받는다. 입력받은 수는 1~9사이의 수여야만 한다.
    - [ ] 입력받은 3자리 수로 Strike, Ball을 판별한다
    - [ ] 구해진 Strike, Ball을 사용자에게 보여준다.
    - [ ] 스트라이크가 3개 나올때까지 반복한다.

     

    첫 번째로 랜덤으로 1~9까지의 숫자 3개를 생성하는 기능을 구현하겠습니다.

    1단계 : 실패하는 테스트 만들기

    package random
    
    import org.junit.jupiter.api.Assertions
    import org.junit.jupiter.api.Test
    
    class RandomTest {
    
        @Test
        fun `랜덤으로 1~9까지의 숫자가 생성된다`() {
            //given
            val generateRandomNumber = GenerateRandomNumberForTest(3)
    
            //when
            val result = generateRandomNumber.makeRandomNumber()
    
            //then
            Assertions.assertEquals(result, 3)
        }
    
        @Test
        fun `1~9까지의 수가 아니라면 IllegalArgumentException()이 발생한다`() {
            //given
            val generateRandomNumber = GenerateRandomNumberForTest(10)
    
            //when, then
            Assertions.assertThrows(IllegalArgumentException::class.java) {
                generateRandomNumber.makeRandomNumber()
            }
        }
    
        class GenerateRandomNumberForTest(
            private val number: Int,
        ) : RandomUtil {
            override fun makeRandomNumber(): Int {
                if(number <LOW_BOUND || number > UPPER_BOUND){
                    throw IllegalArgumentException()
                }
                return number
            }
    
            companion object{
                const val LOW_BOUND = 1
                const val UPPER_BOUND = 9
            }
        }
    
    }

     

    2단계 : 테스트가 성공하도록 구현

    interface RandomUtil {
        fun makeRandomNumber() : Int
    }

     

    테스트는 성공하지만 실제 구현 로직은 아무것도 구현된 것이 없습니다.

    따라서 실제 구현 로직을 구현하지만 이는 테스트와 무관하다고 생각이 들긴 합니다.

    package random
    
    import java.security.SecureRandom
    
    class GenerateRandomNumber : RandomUtil {
    
        override fun makeRandomNumber(): Int {
            val number = generateRandomNumber(LOW_BOUND, UPPER_BOUND)
            validation(number)
            return number
        }
    
        private fun generateRandomNumber(from: Int, to: Int) = secureRandom.nextInt(to - from) + from
    
        private fun validation(number: Int) {
            if (number < LOW_BOUND || number > UPPER_BOUND) {
                throw IllegalArgumentException()
            }
        }
    
        companion object {
            const val LOW_BOUND = 1
            const val UPPER_BOUND = 9
            private val secureRandom = SecureRandom()
        }
    }

     

    3단계 : 리팩터링

    makeRandomNumber의 이름을 다시 보았을 때 조금 어색함이 느껴졌습니다.

    실제로 validation까지 하기 때문에 genRandomNumberAndValidation()으로 변경하였습니다.

    Random값이 만들어내는 수의 검증은 RandomUtil 구현체에서 이루어져야 지는 것이 적합하다고 판단하여 다음과 같은 리팩터링을 거쳤습니다.

     

    두 번째로 사용자에게 3자리 숫자를 입력받으며, 입력받은 수는 1~9 사이의 수여야만 한다를 구현하겠습니다.

    1단계 : 실패하는 테스트 만들기

    package domain
    
    import input.InputUtil
    import org.junit.jupiter.api.Assertions
    import org.junit.jupiter.api.Test
    import org.junit.jupiter.params.ParameterizedTest
    import org.junit.jupiter.params.provider.ValueSource
    
    class UserTest {
    
        @Test
        fun `사용자는 임의의 3개의 수를 입력할 수 있다`() {
            //given
            val user = User(InputForTest())
    
            //when
            val result = user.inputNumber()
    
            //then
            Assertions.assertEquals(result, "123")
        }
    
        @ParameterizedTest
        @ValueSource(strings = ["135", "459", "562"])
        fun `1~9사이의 임의의 숫자 3개는 유효성 검사에 통과한다`(input: String) {
            //given
            val user = User(InputForTest())
    
            Assertions.assertDoesNotThrow() {
                //when
                user.validation(input)
            }
        }
    
        @ParameterizedTest
        @ValueSource(strings = ["190","900","350","407"])
        fun `0을 입력한 경우에는 유효성 검사에 통과하지 못한다`(input: String){
            //given
            val user = User(InputForTest())
    
            //then
            Assertions.assertThrows(IllegalArgumentException::class.java){
                //when
                user.validation(input)
            }
        }
    
        @ParameterizedTest
        @ValueSource(strings = ["1234","5678","9999","15487165","12","1"])
        fun `3자리가 아닌 경우를 입력한 경우에는 유효성 검사에 통과하지 못한다`(input: String){
            //given
            val user = User(InputForTest())
    
            //then
            Assertions.assertThrows(IllegalArgumentException::class.java){
                //when
                user.validation(input)
            }
        }
    
        @ParameterizedTest
        @ValueSource(strings = ["som","56a","99!","1 3"])
        fun `숫자가 아닌 문자를 입력한 경우 유효성 검사에 통과하지 못한다`(input: String){
            //given
            val user = User(InputForTest())
    
            //then
            Assertions.assertThrows(IllegalArgumentException::class.java){
                //when
                user.validation(input)
            }
        }
    
    
    
        class InputForTest : InputUtil {
            override fun inputNumber(): String {
                return "123"
            }
        }
    }

    @ParameterizedTest를 사용하기 위해서는 gradle 의존성을 추가해야 합니다.

     

    2단계 : 테스트가 성공하도록 구현

    package domain
    
    import input.InputUtil
    
    class User(
        private val inputNumber: InputUtil
    ) {
    
        fun inputNumber(): String {
            return inputNumber.inputNumber()
        }
    
        fun validation(input: String) {
            if (input.length != VALIDATION_INPUT_SIZE) {
                throw IllegalArgumentException()
            }
    
            if (input.contains(ZERO)) {
                throw IllegalArgumentException()
            }
    
            if (!isNumeric(input)) {
                throw IllegalArgumentException()
            }
        }
    
        private fun isNumeric(toCheck: String): Boolean {
            return toCheck.all { char -> char.isDigit() }
        }
    
        companion object {
            const val VALIDATION_INPUT_SIZE = 3
            const val ZERO = "0"
        }
    
    }

     

    3단계 : 리팩터링

    사용자가 음수를 입력할 수 있다고 생각하여 음수에 관련한 테스트도 추가해 주었습니다.

        @ParameterizedTest
        @ValueSource(strings = ["-12", "-96", "-81"])
        fun `음수를 입력한 경우에도 유효성 검사에 통과하지 못한다`(input: String) {
            //given
            val user = User(InputForTest())
    
            //then
            Assertions.assertThrows(IllegalArgumentException::class.java){
                //when
                user.validation(input)
            }
        }

     

    세 번째로 입력받은 3자리 수로 Strike, Ball을 판별하는 하는 기능을 구현하겠습니다.

    1단계 : 실패하는 테스트 만들기

    package domain
    
    import org.junit.jupiter.api.Assertions
    import org.junit.jupiter.api.Test
    import org.junit.jupiter.params.ParameterizedTest
    import org.junit.jupiter.params.provider.ValueSource
    
    class refereeTest {
    
        @ParameterizedTest
        @ValueSource(strings = ["111", "222", "333"])
        fun `3자리수가 모두 일치하는 경우 심판은 3스트라이크 0볼을 반환한다`(input: String) {
            //given
            val referee = Referee(input)
    
            //when
            val result = referee.judge(input)
    
            //then
            Assertions.assertEquals(result.strikeCount, 3)
            Assertions.assertEquals(result.ballCount, 0)
        }
    
        @Test
        fun `3자리수가 모두 일치하지 않는 경우 심판은 0스트라이크, 0볼을 반환한다`() {
            //given
            val answerNumber = "123"
            val referee = Referee(answerNumber)
            val userInput = "456"
    
            //when
            val result = referee.judge(userInput)
    
            //then
            Assertions.assertEquals(result.strikeCount, 0)
            Assertions.assertEquals(result.ballCount, 0)
        }
    
        @Test
        fun `1자리수가 일치하고 2자리는 위치가 일치하는 않는 경우 2볼1스트라이크를 반환한다`() {
            //given
            val answerNumber = "123"
            val referee = Referee(answerNumber)
            val userInput = "132"
    
            //when
            val result = referee.judge(userInput)
    
            //then
            Assertions.assertEquals(result.strikeCount, 1)
            Assertions.assertEquals(result.ballCount, 2)
        }
    
        @Test
        fun `1자리수만 일치하는 경우에는 1스트라이크를 0볼을 반환한다`() {
            //given
            val answerNumber = "123"
            val referee = Referee(answerNumber)
            val userInput = "196"
    
            //when
            val result = referee.judge(userInput)
    
            //then
            Assertions.assertEquals(result.strikeCount, 1)
            Assertions.assertEquals(result.ballCount, 0)
        }
    
        @Test
        fun `1자리수만 위치가 일치하지 않는 경우 1볼을 반환한다`() {
            //given
            val answerNumber = "123"
            val referee = Referee(answerNumber)
            val userInput = "396"
    
            //when
            val result = referee.judge(userInput)
    
            //then
            Assertions.assertEquals(result.strikeCount, 0)
            Assertions.assertEquals(result.ballCount, 1)
        }
    
    }

    Ball, Strike를 판별하는 Referee 클래스를 만들어서 숫자 2개를 주면 strikeCount, ballCount를 검증할 수 있도록 역할 위임

    초기에는 "낫싱", "3 스트라이크" 등을 반환하였으나 이런 것들은 View 클래스에게 위임할 생각으로 strikeCount와 ballCount만 반환하도록 하였습니다.

     

    2단계 : 테스트가 성공하도록 구현

    package domain
    
    import dto.RefereeResponse
    
    class Referee(
        private val answerNumber: String,
    ) {
        fun judge(userInput: String): RefereeResponse {
            val ballCount = countBalls(userInput)
            val strikeCount = countStrikes(userInput)
            return RefereeResponse(
                strikeCount = strikeCount,
                ballCount = ballCount,
            )
        }
    
        private fun countStrikes(userInput: String): Int {
            var strikeCount = 0
            for (index in userInput.indices) {
                strikeCount += strikeCountByIndex(index, userInput)
            }
            return strikeCount
        }
    
        private fun strikeCountByIndex(index: Int, userInput: String): Int {
            if (answerNumber[index] == userInput[index]) {
                return 1
            }
            return 0
        }
    
        private fun countBalls(userInput: String): Int {
            var ballCount = 0
            for (index in userInput.indices) {
                ballCount += ballCountByIndex(index, userInput)
            }
            return ballCount
        }
    
        private fun ballCountByIndex(index: Int, userInput: String): Int {
            if (answerNumber[index] != userInput[index] && answerNumber.contains(userInput[index])) {
                return 1
            }
            return 0
        }
    }

     

    3단계 : 리팩터링 - Kotlin Code Convention에 따라 control-flow-statements 변경

       private fun ballCountByIndex(index: Int, userInput: String): Int {
            if (answerNumber[index] != userInput[index] &&
                answerNumber.contains(userInput[index])
            ) {
                return 1
            }
            return 0
        }

     

    네 번째로 구해진 Strike, Ball을 사용자에게 보여주는 것을 구현하겠습니다.

    1단계 : 실패하는 테스트를 작성하겠습니다

    package view
    
    import dto.RefereeResponse
    import org.junit.jupiter.api.AfterEach
    import org.junit.jupiter.api.Assertions
    import org.junit.jupiter.api.Assertions.assertEquals
    import org.junit.jupiter.api.BeforeEach
    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
    import java.io.ByteArrayOutputStream
    import java.io.PrintStream
    import java.util.function.Consumer
    import java.util.stream.Stream
    
    class OutputViewTest {
    
        private val byteArrayOutputStream = ByteArrayOutputStream()
        private val standardOut: PrintStream = System.out
    
        @BeforeEach
        fun setupStream(){
            System.setOut(PrintStream(byteArrayOutputStream))
        }
    
        @AfterEach
        fun initStream(){
            System.setOut(standardOut)
            byteArrayOutputStream.reset()
        }
    
        @Test
        fun `출력 테스트 튜토리얼`() {
            val name = "까오기"
            val c = Consumer { nm: String ->
                println(
                    nm + "님 안녕하세요."
                )
            }
            c.accept(name)
            assertEquals("까오기님 안녕하세요.", byteArrayOutputStream.toString().trim())
        }
    
    
        @ParameterizedTest
        @MethodSource("provideStrikeCountAndBallCount")
        fun `사용자는 strike, ball의 여부를 console을 통해 확인할 수 있다`(strikeCount : Int, ballCount : Int){
            printStrikeCountAndBallCountTest(
                strikeCount = strikeCount,
                ballCount = ballCount,
                expectedPrint = "${ballCount}볼${strikeCount}스트라이크"
            )
        }
    
        @Test
        fun `3스트라이크 0볼인 경우에는 3스트라이크만 출력한다`(){
            //given
            val strikeCount = 3
            val ballCount = 0
    
            //when,then
            printStrikeCountAndBallCountTest(
                strikeCount = strikeCount,
                ballCount = ballCount,
                expectedPrint = "3스트라이크"
            )
        }
    
        @Test
        fun `0스트라이크 3볼인 경우에는 3볼만 출력한다`(){
            //given
            val strikeCount = 0
            val ballCount = 3
    
            //when,then
            printStrikeCountAndBallCountTest(
                strikeCount = strikeCount,
                ballCount = ballCount,
                expectedPrint = "3볼"
            )
        }
    
        @Test
        fun `0스트라이크 0볼인 경우에는 낫싱을 출력한다`(){
            //given
            val strikeCount = 0
            val ballCount = 0
    
            //when,then
            printStrikeCountAndBallCountTest(
                strikeCount = strikeCount,
                ballCount = ballCount,
                expectedPrint = "낫싱"
            )
        }
    
        private fun printStrikeCountAndBallCountTest(strikeCount : Int, ballCount : Int, expectedPrint : String){
            //given
            val refereeResponse = RefereeResponse(
                strikeCount = strikeCount,
                ballCount = ballCount,
            )
    
            val outputView = OutputView()
    
            val expectedPrint = expectedPrint
    
            //when
            outputView.printStrikeAndBallCount(refereeResponse)
    
            //then
            Assertions.assertEquals(byteArrayOutputStream.toString().trim(), expectedPrint)
        }
    
        companion object{
            @JvmStatic
            fun provideStrikeCountAndBallCount() : Stream<Arguments> {
                return Stream.of(
                    Arguments.of(1,1),
                    Arguments.of(2,1),
                    Arguments.of(1,2),
                )
            }
        }
    }

     

    여기서 고민한 점은 "사용자에게 보여주는 print문을 어떻게 테스트할 것인가?"였습니다.

    간단하게 출력하는 구문을 반환하는 코드를 작성할지, print문을 테스트할 수 있는 방법이 있는지 검색하여 보았습니다.

     

    예전에는 input 테스트를 진행할 때 InputUtil 인터페이스를 만들고 DI를 통하여 Input 클래스를 주입하는 방식으로 구현하여 가짜 Input 클래스를 실제 테스트 때 사용하는 방식을 사용하였는데 input 또한 테스트가 가능함을 알게 되었습니다.

    https://sakjung.tistory.com/33

     

    System.in과 System.out에 대한 테스트

    우테코 자동차 경주 콘솔게임을 구현하면서 특히 단위 테스트 작성 연습에 집중했다. 이제 어느정도 단위 테스트에 대해 자신감이 차올랐을 때 문득 궁금한 점이 생겼다. System.in과 System.out 관

    sakjung.tistory.com

     

    또한 methodSource라는 것을 알게 되어 활용하였습니다.

    https://stackoverflow.com/questions/57054115/use-pure-kotlin-function-as-junit5-methodsource

     

    Use pure Kotlin function as Junit5 methodsource

    I am curious if in the Kotlin, in the parameterized tests in Junit5, i can use the method outside the class as the @MethodSource. I know about 2 ways to use @MethodSource in Kotlin - companion obj...

    stackoverflow.com

     

    2단계 : 테스트가 성공하도록 구현

    package view
    
    import dto.RefereeResponse
    
    class OutputView {
        fun printStrikeAndBallCount(refereeResponse: RefereeResponse) {
            if (refereeResponse.strikeCount == MAXIMUM_COUNT) {
                println(threeStrikeMessage)
                return
            }
            if (refereeResponse.ballCount == MAXIMUM_COUNT) {
                println(threeBallMessage)
                return
            }
            if (refereeResponse.strikeCount == ZERO_COUNT &&
                refereeResponse.ballCount == ZERO_COUNT
            ) {
                println(noBallAndNoStrikeMessage)
                return
            }
            println("${refereeResponse.ballCount}볼${refereeResponse.strikeCount}스트라이크")
        }
    
        companion object {
            private const val MAXIMUM_COUNT = 3
            private const val ZERO_COUNT = 0
            private const val threeStrikeMessage = "3스트라이크"
            private const val threeBallMessage = "3볼"
            private const val noBallAndNoStrikeMessage = "낫싱"
        }
    }

     

    마지막으로 스트라이크 3개가 나올 때까지 게임을 반복하는 기능을 구현하겠습니다.

    1단계 : 실패하는 테스트 작성

    package game
    
    import org.junit.jupiter.api.Assertions
    import org.junit.jupiter.params.ParameterizedTest
    import org.junit.jupiter.params.provider.Arguments
    import org.junit.jupiter.params.provider.MethodSource
    import org.junit.jupiter.params.provider.ValueSource
    import java.util.stream.Stream
    
    class BaseBallGameTest {
        @ParameterizedTest
        @ValueSource(strings = ["123", "456", "259"])
        fun `스트라이크 3개가 나오면 게임이 끝난다`(input: String) {
            //given
            val baseBallGame = BaseBallGame()
    
            //when
            val result = baseBallGame.isAllStrike(input, input)
    
            //then
            Assertions.assertTrue(result)
        }
    
        @ParameterizedTest
        @MethodSource("provideStrikeNumberAndUserInputNumber")
        fun `스트라이크 3개가 아니라면 게임이 끝나지 않는다`(answerNumber: String, userInputNumber: String) {
            //given
            val baseBallGame = BaseBallGame()
    
            //when
            val result = baseBallGame.isAllStrike(answerNumber, userInputNumber)
    
            //then
            Assertions.assertFalse(result)
        }
    
        companion object {
            @JvmStatic
            fun provideStrikeNumberAndUserInputNumber(): Stream<Arguments> {
                return Stream.of(
                    Arguments.of("123", "143"),
                    Arguments.of("125", "123"),
                    Arguments.of("987", "187"),
                )
            }
        }
    
    
    }

     

    2단계 : 테스트가 성공하도록 구현

    package game
    
    class BaseBallGame {
        fun isAllStrike(answerNumber: String, userInputNumber: String): Boolean {
            return answerNumber == userInputNumber
        }
    }

     

    리팩터링 및 애플리케이션 조립하기

    TDD 사이클을 수행하며 만들어낸 애플리케이션을 조립하여 야구게임이 진행하도록 만들고 리팩터링을 수행하겠습니다.

     

    package game
    
    import domain.Referee
    import domain.User
    import input.InputNumber
    import random.GenerateRandomNumber
    import view.InputView
    import view.OutputView
    
    class BaseBallGame {
    
        private val generateRandomNumber = GenerateRandomNumber()
        private val inputNumber = InputNumber()
        private val inputView = InputView()
        private val outputView = OutputView()
    
        fun run() {
            val user = User(inputNumber)
            val answerNumber = makeRandomAnswerNumber()
            val referee = Referee(answerNumber)
    
            do {
                inputView.showInputGuideMessage()
                val userInputNumber = userInputAndValidation(user)
                val judgeResult = referee.judge(userInputNumber)
                outputView.printStrikeAndBallCount(judgeResult)
            } while (!isAllStrike(answerNumber, userInputNumber))
        }
    
        private fun userInputAndValidation(user: User): String {
            val userInputNumber = user.inputNumber()
            user.validation(userInputNumber)
            return userInputNumber
        }
    
        private fun makeRandomAnswerNumber(): String {
            val firstRandomNumber = generateRandomNumberAndToString()
            val secondRandomNumber = generateRandomNumberAndToString()
            val lastRandomNumber = generateRandomNumberAndToString()
            return firstRandomNumber + secondRandomNumber + lastRandomNumber
        }
    
        private fun generateRandomNumberAndToString(): String {
            return generateRandomNumber.getRandomNumberAndValidation().toString()
        }
    
    
        private fun isAllStrike(answerNumber: String, userInputNumber: String): Boolean {
            return answerNumber == userInputNumber
        }
    }

    BaseBallGame 클래스를 만들고 User, Referee, inputNumber, generateRandomNumber 등 역할을 분담시킵니다.

     

    이후 isAllStrike의 경우에도 private 하게 만들어주고 reflection을 활용해서 테스트 코드를 리팩터링 하였습니다.

     

    하지만 막상 짜고 보니  BaseBallGame이 추상화에 의존하지 않고 구현체에 의존하고 있기 때문에 추상화에 의존하도록 변경해보려고 합니다.

     

    인터페이스를 도입하고 DI를 통해 BaseBallGame에 주입하는 형태로 변경하여 테스트하기 용이한 구조로 변경하였습니다.

     

    따라서 사용자가 매번 input값을 주는 것에 따라 변할 수 있는 run메서드를 테스트할 수 있게 되었습니다.

     

     

    Strike, Ball, 낫싱에 대한 Enum 도입 리팩터링

    문자열로 사용하던 Strike, Ball, 낫싱에 대해 Enum을 도입하면 좋을 것 같다고 생각이 들었습니다.

    이유는 Strike, Ball, 낫싱에 대한 변경 포인트를 가지기 위함입니다.

     

    enum class RefereeDiscriminate(val discriminate : String) {
        STRIKE("스트라이크"),
        BALL("볼"),
        NOTHING("낫싱"),
    }
    
    //Enum 활용법
    RefereeDiscriminate.STRIKE.discriminate == "스트라이크"

     

     

    Git Repo

    https://github.com/Junuu/Number-BaseBall-Game-TDD

     

    GitHub - Junuu/Number-BaseBall-Game-TDD: 숫자 야구 게임을 코틀린 + TDD로 구현해보기

    숫자 야구 게임을 코틀린 + TDD로 구현해보기. Contribute to Junuu/Number-BaseBall-Game-TDD development by creating an account on GitHub.

    github.com

     

     

     

     

     

     

    출처

    https://ksabs.tistory.com/220

     

    [우테코 프리코스] 1주차: 숫자 야구 게임

    🚀 기능 요구사항 기본적으로 1부터 9까지 서로 다른 수로 이루어진 3자리의 수를 맞추는 게임이다. 같은 수가 같은 자리에 있으면 스트라이크, 다른 자리에 있으면 볼, 같은 수가 전혀 없으면

    ksabs.tistory.com

    https://www.baeldung.com/kotlin/check-if-string-is-numeric

     

    Check if a String Is Numeric in Kotlin | Baeldung on Kotlin

    A quick and practical guide to checking if String is numeric in Kotlin.

    www.baeldung.com

    https://kotlinlang.org/docs/coding-conventions.html#control-flow-statements

     

    Coding conventions | Kotlin

     

    kotlinlang.org

    https://sakjung.tistory.com/33

     

    System.in과 System.out에 대한 테스트

    우테코 자동차 경주 콘솔게임을 구현하면서 특히 단위 테스트 작성 연습에 집중했다. 이제 어느정도 단위 테스트에 대해 자신감이 차올랐을 때 문득 궁금한 점이 생겼다. System.in과 System.out 관

    sakjung.tistory.com

    https://stackoverflow.com/questions/57054115/use-pure-kotlin-function-as-junit5-methodsource

     

    Use pure Kotlin function as Junit5 methodsource

    I am curious if in the Kotlin, in the parameterized tests in Junit5, i can use the method outside the class as the @MethodSource. I know about 2 ways to use @MethodSource in Kotlin - companion obj...

    stackoverflow.com

     

    댓글

Designed by Tistory.