본문 바로가기

TDD(2) - 첫 작성해보기

@정소민fan2025. 10. 16. 21:56

TDD를 한번 해보자

처음 해보는거라 막상 손을 대보려니 막막했다.

 

일단 과제로 주신 코드에는 DB관련 로직이 모두 구현되어있었다.

그러면 리포지토리를 먼저 테스트해봐야하나... 근데 이미 코드가 작성되어있는건데 내가 테스트를 작성해야할 필요가 있을까?

제약조건에 리포지토리를 건들지 말라고도 적혀있으니 그냥 넘어가기로 했다.

테스트 틀리면 어떡할건데? 건들지도 못하는데! 라는 마인드

 

과제는 포인트 관련 증감/조회 연산을 구현하는 것

 

그래서 서비스 레이어부터 테스트해보기로 했다.

테스트를 먼저 작성하라고 했지?

근데 정작 Mock을 제대로 써본적이 없어서 여기저기 긁어모아서 어떻게 하는지 참고하고 작성했다.

@ExtendWith(MockitoExtension::class)
class PointServiceTest {
	...

@ExtendWith(MockitoExtension::class

Junit5에서 Mockito를 사용하기 위한 어노테이션이라고 한다

    @InjectMocks
    private lateinit var pointService: PointService

    @Mock
    private lateinit var userPointTable: UserPointTable

@InjectMocks

테스트 대상이 되는 객체를 선언한다. 이렇게 해 두면 이 객체가 생성될 때 의존하는 객체를 가짜로 만들어 주입받게 해 준다

@Mock

@InjcetMocks가 의존하는 Mock 객체를 선언한다. userPointTable을 가짜로 만들 수 있다.

 

포인트 관련 증감 연산부터 구현하기로 했다. 일단 증가부터

private val mockUserId: Long = 1L
private val mockUserPoint: Long = 1000L
private val time: Long = 3000L

private fun makeMockUserPoint(changePoint: Long): UserPoint{
    return UserPoint(
        mockUserId,
        mockUserPoint + changePoint,
        time
    )
}

먼저 이렇게 고정적으로 사용할 변수들과 함수부터 만들어놨다. 테스트 함수를 작성할때마다 변수들을 일일히 작성해두면 굉장히 번거로울 거 같다. 결과값만 테스트마다 다르게 작성하기로 했다.

@Test
fun 포인트가_정상적으로_증가() {
    val increasePoint = 1000L
    val userPoint = makeMockUserPoint(increasePoint)
    given(userPointTable.insertOrUpdate(mockUserId, increasePoint)).willReturn(userPoint)

    val resultUserPoint : UserPoint = pointService.increasePoint(mockUserId, increasePoint)

    assertThat(userPoint.id).isEqualTo(resultUserPoint.id)
    assertThat(userPoint.point).isEqualTo(resultUserPoint.point)
    then(userPointTable).should(times(1)).insertOrUpdate(mockUserId,increasePoint)
}

실제 UserPointTable의 insertOrUpdate는 UserPoint 클래스를 반환한다. 미리 선언해둔 makeMockUserPoint 함수를 통해 결과값으로 기대되는 UserPoint 클래스를 만들어두고, given 함수를 사용해 Mock 객체인 userPointTable의 insertOrUpdate가 해당 클래스를 반환하도록 설정해둔다. 이로 인해 실제 UserPointTable은 이 테스트에 전혀 참여하지 않는다.

 

그 다음 PointService의 increasePoint를 실행한다. 물론 PointService는 아직 작성하지도 않았다. TDD는 항상 테스트를 먼저 작성해야하니까

 

assertThat으로 기대되는 결과값을 비교하고, then으로 UserPointTable의 insertOrUpdate가 1번 동작할것이라 작성해둔다.

 

이제 PointService의 increasePoint 를 작성해보자. 사실 이 함수에 별다른 비즈니스 로직은 필요하지 않을 것 같다.

@Service
class PointService(
    private val userPointTable: UserPointTable
) {
    fun increasePoint(userId: Long, increasePoint: Long): UserPoint {
        return userPointTable.insertOrUpdate(userId, increasePoint)
    }
}

그래서 그대로 userPointTable의 insertOrUpdate를 호출하여 반환하는 식으로 작성했다.

테스트 결과는?

통과 완료

 

첫 TDD라서 작성해봤는데, 처음 써보는 방식이라 좀 생소하긴 하다. 나머지 테스트도 작성하고 포스팅하겠다.

정소민fan
@정소민fan :: 코딩은 관성이야

코딩은 관성적으로 해야합니다 즐거운 코딩 되세요

목차