BackEnd/TDD

[TDD] 테스트를 위한 생성자, 메서드 피하는 방법

샤아이인 2022. 7. 26.

스스로 공부하다 경험했던 문제를 해결하기 위해 

 

1. 문제 상황

테스트를 작성하다 보면 검증을 위해 id값을 직접 객체에 추가해줘야 하는 경우들이 있다.

 

하지만 JPA를 사용할 경우 프로덕션 코드에서는 생성자로 id를 직접 추가해주지 않아도, auto increment를 사용하게 되기 때문에 id값을 직접 할당할 필요가 없다.

 

따라서 단지 테스트 만을 위한 용도로 id값을 받는 생성자를 만들게 되는 점이 매우 거슬렸다.


예시를 통해 문제의 상황을 구체화 해보자!

우선 우리의 도메인을 시각화하면 다음과 같다.

 

다음과 같은 예시 코드를 살펴보자.

@DisplayName("구간을 성공적으로 추가한다")
@Test
public void add_section_test() {
    // given
    Line line = new Line("2호선", "green");
    Station upStation = new Station("강남역");
    Station downStation = new Station("건대입구역");

    Section originSection = new Section(1L, line, upStation, downStation, 10);

    Sections sections = new Sections();

    // when
    sections.add(originSection);

    // then
    assertThat(sections.getStations()).containsExactly(upStation, downStation);
}

2호선을 만들고, 강남역과 건대입구역을 만든 후, originSection을 만들어서, sections에 추가하게 된다.

 

이후 then 절에서 assertThat을 통해 upStation(강남역), downStation(건대입구역) 있는지 확인한다.

 

sections에는 2호선 하나만 추가되어 있기 때문에 역 목록을 조회하면 upStation(강남역), downStation(건대입구역) 이 조회될 것이다.

따라서 위 코드는 정상적으로 수행될 것 같다!

 

하지만 실행해보면 다음과 같은 결과가 나온다.

 

테스트가 실패했음을 알 수 있다. 왜 이런 상황이 발생한 것 일까?

이는 Station Class의 equls&hash 가 다음과 같이 ID를 기반으로 검증하고 있기 때문이다.

 

따라서 다음과 같이 Station 들에게 테스트용으로 ID값을 부여하면 테스트는 정상적으로 통과한다.

 

단순 테스트를 위해 생성자에서 ID를 받도록 코드를 수정하였다....

이러한 부분은 어느 정도 허용 가능하다 생각하시는 분도 있을 것이고, 허용할 수 없다 생각하시는 분도 있을 것이다.

 

이번 글에서는 이런 점을 허용할 수 없다는 입장에서의 대안을 적어볼까 한다.

 

2. 해결 방법

2-1) Stubbing 활용하기

모의 객체 중 Stub을 통해 Stubbing을 정의하면 해결할 수 있다.

말보다는 코드로 살펴보자!

빨간 박스 안을 보면 알 수 있듯, stub을 통해 기대 행위를 개발자가 직접 정의해주고 있다.

 

stub 방식은 개발자가 협력하는 객체들의 상세 구현을 알아야 한다는 단점이 있지만, 하지만 생성자를 통한 id값을 할당하는 방법은 아니기 때문에 우리의 문제를 해결한 방식이라 할 수 있다.

 

2-2) Reflection 활용하기

이번 방식을 Java의 Reflection을 활용해서 사용하는 방식이다. 개인적으로 stub방식보다는 마음에 드는 방식인 것 같다 ㅎㅎ

빨간 박스 안의 메서드에서 Reflection을 통해 해결하고 있다.

 

다만 테스트를 위해 Reflection까지 가져다 사용하는 것이 적합한가? 란 의문은 좀 든다.

 

댓글