TIL(Today I Learned)

TIL - 조회수 증가 테스트 코드에서 조회수가 반영되지 않는 문제 해결

Happy._. 2024. 7. 5. 22:18

조회수 증가 구현을 위해 Repository에 다음 코드를 작성했다.

@Modifying
@Query("UPDATE WikiPage w SET w.views = w.views + 1 WHERE w.id = :wikiId")
fun updateViews(wikiId: Long)

 

그리고 실행했을 때 다음과 같은 예외가 발생했다.

다른 프로젝트에서는 위 쿼리 메서드가 문제없이 실행되었지만 현재 프로젝트에서는 원하는 대로 작동하지 않았다.

query executed via 'getresultlist()' or 'getsingleresult()' must be a 'select' query 
[update wikipage w set w.views = w.views + 1 where w.id = :wikiid]

 

그래서 QueryDSL을 사용해 다음과 같이 구현했다.

fun updateViews(wikiId: Long) {
    queryFactory.update(wikiPage)
        .set(wikiPage.views, wikiPage.views.add(1))
        .where(wikiPage.id.eq(wikiId))
        .execute()
}

 

실행했을 때 정상적으로 조회수가 증가되는 것을 확인했는데 테스트 코드에서는 조회수 반영이 정상적으로 되지 않았다.

실패한 테스트 코드는 다음과 같다.

@Test
fun `게시물 단건 조회를 하는 경우 조회수 증가`() {
    val wikiId = 1L

    wikiPageRepository.updateViews(wikiId)
    wikiPageRepository.flush()

    val result = wikiPageRepository.findByIdOrNull(wikiId)

    result?.views shouldBe 1
}

 

해당 코드가 실패하는 이유는 테스트 코드 수행 전 setup 메서드를 통해 저장되는 데이터들이 영속성 컨텍스트에 저장되는데 위 코드에서 wikiPageRepository.updateViews(wikiId)는 DB에 직접 쿼리를 날린다.

그리고 다시 wikiPageRepository.findByIdOrNull(wikiId)로 데이터를 가져올 때는 DB에서 가져오는 것이 아닌 영속성 컨텍스트에 있는 데이터를 가져오기 때문에 원하는 결과가 나오지 않는 것이다.

@BeforeEach
fun setup() {
    wikiPageRepository.saveAllAndFlush(DEFAULT_WIKIPAGE_LIST)
}

companion object {
    private val DEFAULT_WIKIPAGE_LIST = listOf(
        WikiPage.from(
            request = CreateWikiPageRequest(
                title = "title 1",
                content = "content 1",
                tag = "tag 1"
        )
    )
}

 

이 문제점을 해결하기 위해 엔티티의 데이터를 변경하는 방식으로 코드를 변경했다.

@Entity
@Table(name = "wiki_page")
class WikiPage private constructor(
    // ...
) : BaseTimeEntity() {
    // ...
    var views: Long = 0
        protected set
    // ...
    fun updateViews() {
        this.views += 1
    }
    // ...
}

 

그리고 테스트 코드 또한 다음과 같이 변경했다.

@Test
fun `게시물 단건 조회를 하는 경우 조회수 증가`() {
    val wikiId = 1L
    val wikiPage = wikiPageRepository.findByIdOrNull(wikiId)

    wikiPage?.updateViews()
    wikiPageRepository.saveAndFlush(wikiPage!!)

    val result = wikiPageRepository.findByIdOrNull(wikiId)

    result?.views shouldBe 1
}

 

위와 같이 변경 후 테스트도 정상적으로 수행되고 코드 수도 많이 줄어들었다.