2018-4-3 TIL Java Lotto TDD기반으로 다시 구현하기

TDD기반으로 Lotto 구현하기

LottoTest

public class LottoTest {
    @Test
    public void 자동생성() {
        Lotto lotto = new Lotto();
        int length = lotto.lottoSize();
        assertEquals(6, length);
    }

    @Test
    public void 문자열넣고생성() {
        String winning = "1,2,3,4,5,6";
        Lotto winningNumber = new Lotto(winning);
        int length = winningNumber.lottoSize();
        assertEquals(6, length);
    }

    @Test
    public void 카운팅테스트() {
        Lotto lotto = new Lotto("1,2,3,4,5,6");
        Lotto win = new Lotto("1,2,3,7,8,9");
        int countNumber = lotto.countNumber(win);
        assertEquals(3, countNumber);
    }
}
  • 기존에는 Lotto객체를 생성하고 거기에 생성자를 넣고 Lotto객체를 생성하는 방식으로 접근을 했었다. TDD기반으로 로또 1단계를 다시 구현을 하기 시작을 했는데, 처음에 LottoTest을 먼저 만들어서 테스트 기반으로 진행을 해보았다. 먼저 자동생성이라는 Test를 만들고, 거기서 로또객체를 생성을 하고 6자리가 알맞게 들어갔는지 우선 테스트를 하게 된다.
  • 두번째로는 로또 생성자에 문자열을 입력을 받아서 로또 객체를 생성을 하고 그것을 바탕으로 테스트를 하는 메소드를 만들었다.
  • 세번쨰 메소드는 생성된 로또와 당첨번호를 비교를 해서 맞춘갯수가 정확하게 들어갔는지를 비교하는 테스트이다. 처음 로또를 만들었을때는 WinningLotto를 List형태로 만들어서 Integer.parseInt(WinningLotto.get(i))의 형태로 반복문을 돌면서 비교를 하곤 했었다. 이제는 WinningLotto역시 Lotto객체로 생성을 해서 비교를 하니 훨씬 더 편해졌다.

BuyLottoTest

public class BuyLottoTest {
    @Test
    public void 로또구매() {
        int inputMoney = 14000;
        BuyLotto buy = new BuyLotto(inputMoney);
        int num = buy.getLottos().size();
        assertEquals(14, num);
    }
}

LottoGameTest

public class LottoGameTest {
    @Test
    public void 숫자비교() {
        LottoGame game = new LottoGame();
        List<Lotto> lottos = Arrays.asList(new Lotto("1,2,3,4,7,8"), new Lotto("1,2,3,11,22,33"), new Lotto("17,29,31,11,22,33"));
        Lotto winningNumber = new Lotto("1,2,3,4,5,6");
        List<Integer> counts = game.match(lottos, winningNumber);
        int compare1 = counts.get(0);
        int compare2 = counts.get(1);
        int compare3 = counts.get(2);
        assertEquals(4, compare1);
        assertEquals(3, compare2);
        assertEquals(0, compare3);
    }

    @Test
    public void 맞춘갯수빼오기() {
        LottoGame game = new LottoGame();
        List<Integer> counts = new ArrayList<>();
        counts.add(3);
        counts.add(4);
        counts.add(5);
        counts.add(3);
        int num1 = game.getCount(counts, 3);
        int num2 = game.getCount(counts, 4);
        int num3 = game.getCount(counts, 5);
        assertEquals(2, num1);
        assertEquals(1, num2);
        assertEquals(1, num3);
    }

    @Test
    public void 당첨번호갯수불러오기() {
        LottoGame game = new LottoGame();
        List<Integer> counts = Arrays.asList(1,3,3,4,5);
        List<Integer> winCounts = game.getWinCounts(counts);
        int num1 = winCounts.get(0);
        int num2 = winCounts.get(1);
        int num3 = winCounts.get(2);
        assertEquals(2, num1);
        assertEquals(1, num2);
        assertEquals(1, num3);
    }
}
  • 숫자비교 테스트메소드를 통해서 game.match()를 호출을 했을때, counts에 해당 값들이 잘 들어가는지를 확인하기 위해서 만들었다. counts에는 0-6까지의 맞춘갯수의 번호들이 잘들어간다.
  • 맞춘갯수빼오기에서는 counts에 있는 값들의 갯수가 정확하게 들어갔는지를 테스트를 하는 메소드이다. 처음 로또를 구현했을때, 가장 많이 부딪쳤던 문제중의 하나가 3개, 4개, 5개, 6개를 맞췄을때 거기서 1개는 들어가지만 2개3개가 들어가지 않는 에러가 발생을 했는데 그것을 확인할수 있었다.

오늘의 느낀점

오늘 개인면담을 하고 나서 많은 생각이 들었다. 내 자신이 굉장히 무능력한가라는 회의감도 들었고, 포기를 할 생각은 아니지만 중간에 의도치않게 드랍을 할 수도 있겠구나라는 생각도 들었다. 오늘 면담에서는 나름대로 많은 자극이 됬었다. 나도 내 속도로 알맞게 가려고해도 사람인지라 주변에 같이 공부를 하는 사람들의 속도를 보면 대단하다는 생각이 많이든다. 어떻게하면 저렇게 설계를 잘할 수 있을까. 테스트기반으로 잘 설계를 할 수 있을까에 대한 부러움도 있었다. 나는 아직도 객체도 인스턴스도 잘 모른다는 이야기를 듣고 있는데, 옆에 공부하는 사람들을 보면 정말 잘해서 부럽기도 또 감사하기도 했다. 옆에 배울 수 있다는 사람들이 많은것은 정말 축복이고 감사한일이다. 하지만 그렇게 주변에 잘하는 사람들이 많음에도 불구하고 나는 객체지향이란 무엇인지. 또 객체지향 설계에 대해서 늘 잘 모르고 이해가 부족했다. 거기다 그런소리도 많이 들어왔었다. 내가 객체지향에 대한 고민을 안하고 있다면 문제가 덜 됬을지도 모르겠는데. 평상시에도 객체란 무엇인가에 대한 고민은 늘 하고 있다. 계속하고 있다. 자면서도 하고있는데, 객체지향에 대해서 모른다는것은 내가 잘못된 인식이나 관점을 가지고 있다는 의미이다. 이제는 객체지향의 책들을 통해서 이제부터는 내가 잘못알고 있었던 부분에 대해서 개선을 할 수 있었으면 좋겠다는 희망을 가져본다. 면담이 끝나고 나서 차마 step4를 다시 진행을 할 수가 없었다. 그러다가 ATDD?가 아닌 완전 TDD기반으로 로또 1단계를 한번 다시 설계를 하자고 마음을 먹었다. 늘 다시 설계를 해보는것이 좋고 필요하다고 이야기를 하셨는데, 다시 재설계를 하고 구조를 다시 짠다는것에 대해서는 잘 몰랐다. 구조를 바꾼다는것이 순서를 바꾸고 메소드들을 다른 클래스에 옮기는 것으로만 생각을 했었다. 그 의미를 몰랐기에 로또를 다 업고 처음부터 다시 구현을 해야겠다는 마음이 더 들었던거 같다… TDD에 관한 이야기와 테스트코드에 관한 이야기는 늘 들어왔던 부분이다. 나는 테스트코드에 대한 두려움이 많았다. 그렇기에 테스트코드를 안만든다는 것이 나에게 언젠가 큰 실수를 하게될 것임이라는 것을 의식은 하고있었지만, 크게 와닿지는 않았다. 어쩌면 지금 객체지향도 잘 모르는데, 무슨 테스트코드까지 설계를 하냐라는 나만의 자기변명을 했던거 같다. 이제는 다른관점을 얻고 싶어서 얻기 위해서 테스트코드를 작성을 하고 특히 지난주 목요일에 들었던 TDD의 라이브코딩 방식을 보고서 어떻게 시작을 해야되는지에 대한 시작포인트는 보게 되었다. 금요일에도 혼자서 테스트코드를 작성하는 연습을 했었는데, 목요일에 본것처럼 나도 TDD로 로또를 설계를 해봐야겠다는 생각이 들어서 일단 시작은 했다. 죽이되든 밥이되든 한번 해보자하고서 시작을 했다. 기존설계와 달라진부분이 있다면 이전에는 프로그램을 설계를 할때, Main클래스와 Lotto클래스, Input클래스들을 먼저 만들어두고 설계를 해나아갔었다. 그러다가 이번에는 아예 LottoTest를 먼저 만들고 거기서 내가 어떤 테스트를 할것이며 테스트를 위해서 무엇이 필요한지에 대해서 하나둘씩 쳐가면서 진행을 하게되었다. 그러면서 Lotto의 생성자를 통해서 Lotto객체를 만드는것이 필요해서 Lotto생성자를 설계를 하게 되고, 문자열을 넣고 로또를 생성을 하는것을 테스트를 하기위해 Lotto생성자에 String타입을 받는 생성자도 추가를 하고 테스트를 진행을 하게 되었다. 결국에는 내가 프로그램을 설계하기 위해서 필요한 테스트들을 미리 작성을 하고 그것을 테스트하기 위해서 클래스설계를 하는 방식으로 접근을 하게 됬다. 그러다보니 생각보다 빨리 설계를 하게 되었고, 이전에 내가 수동테스트를 할때 못잡았던 문제들에 대해서 금방금방 문제를 캐치하기 시작을 했다. 캐치한 문제를 바탕으로 그것에 해당하는 메소드를 수정해 나가는 식으로 로또 프로그램 step1을 마무리하게 되었다. step2역시도 TDD기반으로 잘 설계를 해서 이전보다는 좀 더 객체지향적이라고 말할 수 있었으면 좋겠다.

잡담

개인은 누구나 문제를 가지고 살아간다. 그 문제를 어떻게 대하는 태도에 따라서 그 사람의 인생이 달라지고 결정이 된다고 생각을 하고 평소 그런 신념을 바탕으로 삶을 지향하고 있다. 오늘 문제를 직면하지 않고 편안게 편안거지라는 내 자신을 발견을 하게 되었다. 왜 나는 프로그래밍에 있어서는 변화를 하려고 하지 않은걸까? 모른다고 변명을 하고 싶은건지 아니면 어려워서 익숙하지 않아서 그렇다고 이야기를 하고 싶은건지. 이유와 동기가 어찌됬던간에 나는 프로그래밍에 있어서 어쩌면 삶 전체적으로 바라보았을 때 변화를 거부하고 문제를 회피를 하게 되는 내 자신을 발견을 하게되었다. 그런 내 자신과 직면을 하게되었을때, 굉장히 화가 많이 났었다. 내가 정말 변화를 거부하고 무능력하고 한심한 자신이였구나 싶었다. 내가 아무리 문제를 회피를 한다고 할지라도 결국에는 그 문제는 언젠가 내 발목을 붙잡게되어있고 점점 더 크게 영향을 미치고 나중에는 헤어나올 수 없이 내 자신을 구렁텅이로 넣을거라는 생각을 하게된다. 하루라도 빨리 이런 내 자신의 태도를 바꾸고 개선을 해야겠다. 이전에는 속도가 느리면 나만의 페이스대로 간다고 이야기를 했었다. 지금은 나만의 페이스가 아니라 속도도 느리고 올바르지 않은 방향으로 나아가고 있다는 생각이 든다. 지금이라도 크게 문제의식이 생겨서 감사하다. 이제부터 다시 조금씩 조금씩 생각의 과정을 개선하며 객체지향적으로 잘 나아가야겠다 :)

Written on April 3, 2018