[우아한테크코스 6기] 1주차 미션 회고 - 숫자 야구(feat. 랜덤 상황 테스트)

Jinny·2023년 10월 24일
3

💬 들어가며

우아한테크코스 6기 프리코스에 참여하게 되어 앞으로 4주간을 기록하고자 한다.

이번 1주차 미션은 근본의 숫자 야구 게임이었다.
필자가 작성한 코드는 밑에 첨부한 링크에서 확인 가능하다.

숫자 야구 Github Repository

최근까지 Spring으로 프로젝트를 하다가 순수 Java로만 미션을 진행하니까 색다른 느낌이기도 하고 재미있었다. ㅎㅎ

1주차에는 기본에 충실하면서 남들이 읽기 쉬운 코드를 작성하는 것이 나만의 목표였다.
(과연 읽기 쉬운 코드를 짰는지...는 우테코 디스코드를 통해 PR 리뷰 요청을 해 피드백을 받아볼 예정이다.!)

✏️ PR Review
블로그 보고 들어오시는 분도 있을 것 같아 개인 레포지토리에 리뷰용 PR을 올렸습니다.
↓↓ PR 리뷰는 언제나 환영입니다! ↓↓
https://github.com/jinny-l/java-baseball-6/pull/1

그리고 미션을 구현하면서 전반적인 설계나, 테스트 등 다양한 다양한 고민을 하게 되었다.

본글은 미션을 진행한 과정과 고민등에 대해 기록하고자 한다.
그럼 회고를 시작해보자!




🏃🏻 미션 진행 과정

✨ 기능 목록 작성

"기능을 구현하기 전 docs/README.md에 구현할 기능 목록을 정리해 추가한다."라는 요구사항이 있어
우선 기능 목록을 작성하고 기능 구현을 시작했다.

처음부터 모든 목록을 다 작성한 것은 아니고 구현하면서 누락한 내용이 있으면 그때그때 추가했다.

그리고 커밋할 때 구현한 기능은 to do 박스에 체크하면서 진행했다.

사실 정신없이 구현하다보면 어디까지 구현이 되었고, 어느 부분이 남았는지 헤맬때가 있었다.
머리속에 다음에 뭐 해야하지?라는 갈고리(🤯)가 생겼는데, 이때 기능 목록이 길잡이가 되어주었다.

기능 목록에 따라 하나 하나 구현하다보니 기능 구현이 완료되었다.

README.md
(캡쳐하기에 너무 길어서 일부 내용만 캡쳐했다. 원본은 여기서 확인할 수 있다.)




✅ 테스트 케이스 목록 작성

기능 구현을 다하고 기능 확인을 위해 테스트 코드를 작성했다.

테스트 코드 작성 전에도 기능 목록 작성한 것과 같이 README에 미리 테스트 케이스 목록을 만들었다.

테스트 코드를 짜다보면 어떤 케이스를 테스트했는지, 어떤 케이스를 테스트 안했는지 한눈에 안 보이기도 하고
코드를 짜면서 케이스를 생각하기 어렵다보니 목록을 짜게 되었다.

아직 테스트 코드 짜는 게 어렵지만...
테스트 코드를 짤 때도 케이스가 미리 정리되어 있다보니 한결 수월하게 진행할 수 있었던 것 같다.

README.md
(캡쳐하기에 너무 길어서 일부 내용만 캡쳐했다. 원본은 여기서 확인할 수 있다.)




🔍 공부한 내용과 고민

☕️ Java 17

작년 우테코 요구사항은 Java 11이었는데, 올해는 Java 17로 바뀌었다.
지금까지 Java 11만 썼는데 Java 17을 사용하기 위해 변경점을 공부했다.!

그리고 변경점만 공부하는 것보다는 올해에는 왜 요구사항이 바뀌었고 Java 17을 써야 하는지
알고 쓰는 것이 좋을 것 같아서 관련 내용을 공부하고 블로깅하였다.

[Java] Java 17을 사용해야 하는 이유와 Java 17 변경점

다음 미션에는 Java 17에 추가된 기능을 하나씩 사용해볼 예정이다!




🧐 랜덤으로 생성된 숫자는 어떻게 테스트하지?

숫자 야구는 1부터 9까지 서로 다른 수로 이루어진 3자리의 수로 이루어져 있는데
미션 요구사항을 보면 이 숫자는 제공된 Randoms API를 활용하여 랜덤 값을 추출하여 만들어야 한다.

그때부터 고민이 시작되었다... 🤔

컴퓨터가 생성한 숫자 야구가 있고, 플레이어의 입력 값에 대한 결과(스트라이크, 볼, 낫싱)를 테스트해야 하는데...
숫자가 랜덤으로 생성되면 어떻게 테스트하지..?

랜덤으로 생성된 숫자를 테스트하는 방법에 대해 찾아보다가 좋은 블로그 글을 발견하게 되어 인사이트를 얻게 되었다!

🔗 참고한 블로그:

바로 인테페이스로 추상화하는 것이다..!

  • 랜덤 숫자 생성기를 인터페이스로 추상화하고
  • main에서는 실제로 랜덤으로 숫자를 생성하는 클래스를 구현하고
  • test에서는 의도한 숫자를 생성하는 클래스를 구현하면 테스트하기 수월해진다.

코드로 자세하게 알아보자.

1. 랜덤 숫자 생성기를 인터페이스로 추상화한다.

NumberGenerator.java

@FunctionalInterface
public interface NumberGenerator {

    List<Integer> generate();
}

2. 각 상황에 맞게 인터페이스를 구현한다.

RandomNumberGenerator.java - main에서 사용하는 구현체
: 랜덤 숫자 3개를 리턴하게 구현

@Override
    public List<Integer> generate() {
        List<Integer> numbers = new ArrayList<>();
        while (numbers.size() < BASEBALL_LENGTH) {
            int randomNumber = Randoms.pickNumberInRange(BASEBALL_START_NUMBER, BASEBALL_END_NUMBER);
            if (!numbers.contains(randomNumber)) {
                numbers.add(randomNumber);
            }
        }
        return numbers;
    }

TestNumberGenerator.java - test에서 사용하는 구현체
: 생성자 생성 시 입력받은 값을 그대로 리턴하게 구현


public static class TestNumberGenerator implements NumberGenerator {

        private final List<Integer> numbers;

        TestNumberGenerator(List<Integer> numbers) {
            this.numbers = numbers;
        }

        @Override
        public List<Integer> generate() {
            return numbers;
        }
    }

3. 의도한 테스트를 진행한다.

다음 코드는 실제로 제출한 미션 코드에서 일부를 발췌한 내용이다.
필자는 Service 클래스에서 랜덤 숫자를 생성해 Baseball을 생성하게끔 구현해서 Service 테스트를 했는데, 각자 상황에 맞게 응용하면 될 듯 하다!

public class GameServiceTest {

    private GameService service;

    @BeforeEach
    void setUp() {
    	// ↓ 의도한 숫자를 생성하는 TestNumberGenerator 생성(컴퓨터 Baseball이 1, 2 ,3으로 생성됨)
        service = new GameService(new TestNumberGenerator(List.of(1, 2, 3)));
        service.startGame();
    }

    @DisplayName("낫싱 상황일 때 맞는 결과를 리턴한다.")
    @Test
    void get_nothing_game_result() {
        // given
        service.setPlayerBaseball(List.of(4, 5, 6)); // 플레이어 Baseball을 4, 5, 6으로 생성

        // when
        GameResult gameResult = service.getGameResult();

        // then
        assertThat(gameResult).isEqualTo(GameResult.nothing()); // 낫싱 결과 예상
    }
	
    // ↓ 테스트용 NumberGenerator 구현
    public static class TestNumberGenerator implements NumberGenerator {

        private final List<Integer> numbers;

        TestNumberGenerator(List<Integer> numbers) {
            this.numbers = numbers;
        }

        @Override
        public List<Integer> generate() {
            return numbers;
        }
    }
}



👋 마치며

미션도 해야하고, 공부한 내용 정리하고, 회고까지 하니까 1주일이 뚝딱이다. 🥲

마치기 전에 다음주에 개선하고 싶은 점을 쓰고 회고를 마무리하려고 한다.
이번주 미션하면서 다음 미션에는 꼭 개선해야지 했던 것이 있는데... 바로 테스트 코드이다.

기능 구현이 모두 완료되고 나서 테스트 코드를 짜니까 기능이 제대로 동작하는지 바로바로 확인이 어려웠고,
기능 구현 → 기능 확인 간의 호흡이 너무 긴 느낌이 들었다.

다음 목표는 1기능 1테스트 코드 짜는것을 목표로 진행하려고 한다!

이번 미션에 참여한 분들 모두 고생하셨습니다! 🙇🏻

profile
공부는 마라톤이다. 한꺼번에 많은 것을 하다 지치지 말고 조금씩, 꾸준히, 자주하자.

1개의 댓글

comment-user-thumbnail
2023년 10월 25일

랜덤 숫자 테스트로 저도 애를 먹었는데 비슷한 고민을 하신 분이 있다니 위안이 되네요😂
글 잘 읽었습니다! 코드도 읽어보고 리뷰 남겨 볼게요!📝📝

답글 달기