안녕하세요

피드백 노력해야할 부분 본문

우테코 프리코스/3주차

피드백 노력해야할 부분

sakuraop 2022. 11. 16. 20:05

함수(메서드) 라인은 15라인을 넘지 않도록 한다✔
=> 이때 공백 라인도 한 라인에 해당한다.



예외 상황을 고려해 프로그래밍하는 습관을 들인다✔




비즈니스 로직과 UI로직을 분리한다✔
=> 한 클래스가 담당하지 않도록 한다. 단일 책임의 원칙에도 위배된다.






객체의 상태 접근을 제한한다❌
=> 필드는 private class 필드로 구현한다. 외부에서의 직접 접근을 최소화한다




객체는 객체스럽게 사용한다(????????????)
=> Lotto 클래스는 numbers를 상태 값으로 가진다. 그런데 이 객체는 로직에 대한 구현은 하나도 없고, numbers에 대한 getter 메서드만을 가진다.
(로직에 대한 구현이 없으니 Lotto 클래스는 gtter 메서드만을 갖도록 하고 기능은 다른 클래스(LottoGame)에서 만들어 Lotto에서 가져온 #numbers를 이용하도록 한다???)


Lotto에서 데이터를 꺼내지(get) 말고 메시지를 던지도록 구조를 바꿔 데이터를 가지는 객체가 일하도록 한다
=> Lotto Class에서는 데이터를 꺼내는 것이 아니라 메시지를 주고(return 값), 데이터를 가지는 객체(LottoGame Class)이 일을 하도록 한다
Lotto.contains(number) 
Lotto Class는 .contains() 메서드를 내부에서 실행하지 않고 데이터 결과를 건네주기만 하고
LottoGame Class는 이 메서드를 이용해 받아온 데이터로 일을 하도록 한다.

getter는 멤버변수의 값을 호출하는 메소드이고, setter는 멤버변수의 값을 변경시키는 메소드이다.
클래스의 멤버변수의 접근제어자는 private이며, (=>상태값을 갖는 객체에서는 상태값을 외부에서 직접 접근해 변경하지 못하도록 메소드만 노출시킨다. 직접적인 접근을 막고, getter와 setter를 이용해서만 변수에 접근이 가능하도록 한다.)
모든 멤버변수에 대해 get메소드와 set메소드가 존재해야 한다. 
get메소드는 매개변수가 없어야 하며 set메소드는 하나 이상의 매개변수가 있어야 한다.




필드의 수를 줄이기 위해 노력한다🔺 (리팩토링을 하며 그냥 다 없앨까...? 생각을 했던 만큼 필드를 줄이는 것이 가능함에도 필드의 존재 의의를 파악하지 못해 일부러 생성해버렸다.)
=> 필드의 수가 많은 것은 객체의 복잡도를 높이고, 버그 발생 가능성을 높일 수 있다. 필드에 중복이 있거나, 불필요한 필드가 없는지 확인해 필드의 수를 최소화한다.
필드를 일부러 생성하지 않아도 된다는 것을 알게 된 만큼 로직 내에서 const를 통해 해결해야겠다.





성공하는 케이스 뿐만 아니라 예외에 대한 케이스도 테스트한다✔ (작성 방법을 더 공부해야겠다.)
test("보너스 번호가 당첨 번호와 중복되는 경우에 대한 예외 처리", () => {
   mockQuestions( ["1000", "1,2,3,4,5,6", "6"]);
   expect(() => {
       const app = new App();
       app.play();
   }).toThrow("[ERROR]");
});




테스트 코드도 코드다🔺 (여러 인자를 받기 위해 map으로 구현을 했는데, test.each라는 메서드를 이용하면 훨씬 간단하게 코드를 구현할 수 있었다.)
테스트 코드도 코드이므로 리팩터링을 통해 개선해나가야 한다. 특히 반복적으로 하는 부분을 중복되지 않게 만들어야 한다. 예를 들어 단순히 파라미터의 값만 바뀌는 경우라면 아래와 같이 테스트할 수 있다.

test.each([["999"], ["0"], ["-123"]])("천원 미만의 금액에 대한 예외 처리", (input) => {
   expect((input) => {
     const app = new App(input);
     app.play();
   }).toThrow();
 }
);





테스트를 위한 코드는 구현 코드에서 분리되어야 한다✔ (생각조차도 해보지 않은 부분이었다. 안 하는게 맞다.)
테스트를 위한 편의 메서드를 구현 코드에 구현하지 마라. 아래의 예시처럼 테스트를 통과하기 위해 구현 코드를 변경하거나 테스트에서만 사용되는 로직을 만들지 않는다.

테스트를 위해  # prefix를 바꾸는 경우
테스트 코드에서만 사용되는 메서드





단위 테스트하기 어려운 코드를 단위 테스트하기🔺(랜덤을 어떻게 할 수 없다고 당연하다 여기고 있던 부분이었다. 테스트할 수 있는 부분만 하면 되는 것.)
아래 코드는 Random 때문에 Lotto에 대한 단위 테스트를 하기 힘들다. 단위 테스트가 가능하도록 리팩터링한다면 어떻게 하는 것이 좋을까?
올바른 로또 번호가 생성되는 것을 테스트하기 어렵다. 테스트하기 어려운 것을 클래스 내부가 아닌 외부로 분리하는 시도를 해 본다.
A.
Application(테스트하기 어려움)
     ⬇️
LottoMachine(테스트하기 어려움)
     ⬇️
Lotto(테스트하기 어려움) ➡️ Randoms(테스트하기 어려움)

B.
Application(테스트하기 어려움) 
     ⬇️
LottoMachine(테스트하기 어려움) ➡️ Randoms(테스트하기 어려움) 
     ⬇️
Lotto(테스트하기 쉬움)


(메서드 시그니처를 수정하여 테스트하기 좋은 메서드로 만들기)
ex) 우리가 move 메서드를 테스트하기 좋은 메서드로 만들기 위해서는 먼저 number 변수를 밖으로 빼야 한다. 그렇다면 number 에 의도하는 값을 넣을 수 있고, move 메서드가 number 값에 따라 의도하는 대로 실행하는지 확인할 수 있다.
이전에는 number 변수가 move 메서드 내부에서 랜덤 한 값으로 초기화되었기 때문에 move 가 의도하는 대로 움직이는지 확인할 수 없었다. 그러나 변경된 구조는 number 를 외부에서 주입받기 때문에 어떤 number 값에 따라 move 가 동작하는지 쉽게 테스트할 수 있다.

이처럼 단위 테스트를 할 때 테스트하기 어려운 부분은 분리하고 테스트 가능한 부분을 단위 테스트한다. 테스트하기 어려운 부분은 단위 테스트하지 않아도 된다. 남은 LottoMachine은 어떻게 테스트하기 쉽게 바꿀 수 있을지 고민해 본다.