반응형

1. 과제

 TDD 기반의 회원 관리 REST API를 구현하라.

 

2. 배운점

2.1. Validation

 하나의 DTO에 대해 상황에 맞는 Validation을 체크해야하는 부분이 있었다. 예를들어 유저 최초 생성시에는 모든 필드에 대한 NotBlank를 적용하고, 수정시에는 몇몇 필드에 대한 NotBlank를 적용하는 것과 같은 부분이다.

 사내 프로젝트에 적용할때는 DTO Class를 inner Class로 관리하여 Create, Update Class를 생성하고 각각에 대해 Validation을 적용했었는데 찾아보니 Validation Group을 지정하는 방법이 있어 이를 적용해보았다.

 적용해본 결과 그 방법이 간단하지 않고, 결과적으로 하나의 DTO에 여러 기능들이 응집되어 있는 형태가 되었다. 만약 Validation이 더 추가된다면 거대한 DTO가 될 우려가 있다는 멘토님의 조언을 받을 수 있었다. Validation은 InnerClass가 좋은 방법인 것 같다.

 

2.2. 테스트 커버리지의 목적

 과제가 끝나면 테스트 커버리지를 체크한다. 커버리지를 100%로 맞추려하다보니 비지니스 로직이 없는 DTO도 테스트 클래스를 별도로 만들게 되었는데 이렇게 하다보면 결국 '기존 코드와 테스트코드를 1:1비율로 만들게 되겠는데?' 라는 우려가 들기 시작했다. 테스트 커버리지가 100%가 아니라는 건 뭔가 헛점이 있는 어플리케이션이라는 생각이 들었기 때문이다. 이에 대해 멘토님께서 좋은 참고자료를 주셨는데, 글을 읽어보니 필자처럼 100% 커버리지에 너무 신경쓰는 사람들에 대한 따끔한 조언의 포럼이었다.

 테스트 커버리지의 목적은 '테스트 되지 않는 부분이 있는지 확인'하기 위함이다. DTO의 경우 테스트가 필요 없는 부분이므로 굳이 이에대한 테스트코드를 작성할 필요가 없었다.

 

2.3. Fixture 관리

 테스트 코드 작성 중 중복되는 고정 데이터를 Fixture라고 한다. 예를들어 Update를 위한 객체가 이에 해당하는데 다음과 같이 Builder나 new 생성자를 통해 생성하게 된다.

UserData userData = UserData.builder()
                .name("앙김홍집")
                .email("hongzip@naver.com")
                .password("123123")
                .build();

 BDD 테스트의 경우 사용자의 여러 행동을 예측하여 테스트 코드를 작성하게 되는데 이럴 경우 하드코딩이 들어간 이 로직이 중복되게 되는데 이 경우 Enum을 통해 깔끔하게 관리할 수 있다.

 

public enum UserFixture {

    UPDATE_USER(1L, "앙김홍집","hongzip@naver.com","123123"),
    CREATE_USER(2L, "앙생성집","sangzip@naver.com","12345");

    private final Long id;
    private final String name;
    private final String email;
    private final String password;

    private UserFixture(Long id, String name, String email, String password){
        this.id = id;
        this.name = name;
        this.email = email;
        this.password = password;
    }

    public UserData getUserData(){
        return new UserData(id, name, email, password);
    }

}

 

위와같이 Enum을 만들어 놓고 중복되는 부분에서 호출만해주면 된다. 이를 통해 고정 데이터를 관리할 수 있고, 하드코딩으로 인한 문제도 막을 수 있다.

@Test
@DisplayName("UserNotFoundException 예외를 던진다")
void throwsUserNotFoundException() {
	UserData userData = UserFixture.UPDATE_USER.getUserData();

	assertThatThrownBy(() -> userService.updateUser(INVALID_ID, userData))
		.isInstanceOf(UserNotFoundException.class);
}

 

3. 느낀점

 코드를 짜면서 들었던 찝찝함, 궁금증들을 모두 풀수있어 좋았다. Validation의 경우도 실무에서 적용해보았으나 그 방식에 대해 '이렇게 하는게 과연 맞나?' 라는 찝찝함도 이번 기회를 통해 해소할 수 있었다. 또한 멘토분께서 던져주시는 용어들에 대해 알아가는 과정이 너무 좋았다.

  사실 테스트 코드를 작성하는 건 아직 익숙하지 않다. 먼저 테스트코드를 작성하고 리팩토링하고 로직을 적용하는 방식이 너무 생소하지만 계속 하다보면 이것도 몸에 배겠지? 예전 자바지기님의 TDD 강의를 잠깐 들은 적이 있는데 그분께서 하신 말씀이 생각난다. TDD는 운동처럼 계속 해야한다고, 하다보면 자연스럽게 하게된다고.

반응형

+ Recent posts