Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BookmarkViewModelTest #39

Merged
merged 3 commits into from
Jan 18, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions core/testing/src/main/java/kr/co/testing/dummy/FileInfoDummy.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package kr.co.testing.dummy

import kr.co.model.FileInfo
import kr.co.model.FileInfo.Type.PDF
import java.time.LocalDateTime

val PDF_DUMMY = FileInfo(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트용 데이터를 공유해야하는 이유가 궁금합니다.
A 피처 모듈, B 피처 모듈에서 이것으로 동일하게 테스트를 한다면, 만약 누군가 테스트 데이터를 변경하면 다른 모듈의 테스트 코드가 실패할 수 있을 것 같습니다.
변경된 파일만 테스트를 한다면 이러한 테스트 코드 실패를 늦게 발견하게 될 것 같습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수정하겠습니다

name = "DUMMY.pdf",
path = "",
type = PDF,
isDirectory = false,
isHidden = false,
size = 0,
createdAt = LocalDateTime.now(),
lastModified = LocalDateTime.now()
)

val FOLDER_DUMMY = FileInfo(
name = "DUMMY",
path = "",
type = PDF,
isDirectory = true,
isHidden = false,
size = 0,
createdAt = LocalDateTime.now(),
lastModified = LocalDateTime.now()
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package kr.co.testing.repository

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import kr.co.data.repository.BookmarkRepository
import kr.co.model.FileInfo

class TestBookmarkRepository: BookmarkRepository {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런 특정 도메인/피처와 연관되는 테스트 클래스를 해당 모듈 내에 위치하는 것이 좋을 것 같습니다.
이 구조라면 테스트 모듈이 너무 비대해지고, 모든 피처 모듈을 다 알고 있어야 하기 때문에 테스트 빌드시 시간이 오래걸릴 것 같습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

data모듈에 repsitory interface가 분리되어 data모듈만 바라봐서 모든 피처 모듈은 몰라도 괜찮지 않나요?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(정정 : feature 모듈 -> data 모듈)
repsitory interface를 참조하기 위해 모든 data 모듈을 알고 있는것도 마찬가지로 많은 모듈을 참조하게 됩니다.
testing에서 data 모듈을 알고 있을 필요가 없는것도 같은 맥락에서 동일합니다.


private val bookmarkFilesFlow: MutableStateFlow<List<FileInfo>> =
MutableStateFlow(emptyList())

override suspend fun insert(bookmarkFile: FileInfo) {
bookmarkFilesFlow.update { it + bookmarkFile }
}

override fun get(): Flow<List<FileInfo>> =
bookmarkFilesFlow

override suspend fun delete(bookmarkFile: FileInfo) {
bookmarkFilesFlow.update { it - bookmarkFile }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package kr.co.bookmark

import app.cash.turbine.test
import kotlinx.coroutines.test.runTest
import kr.co.model.BookmarkSideEffect
import kr.co.model.BookmarkUiIntent
import kr.co.testing.dummy.PDF_DUMMY
import kr.co.testing.repository.TestBookmarkRepository
import kr.co.testing.repository.TestRecentRepository
import kr.co.testing.rule.CoroutineTestRule
import org.junit.Before
import org.junit.Rule
import org.junit.Test

internal class BookmarkViewModelTest {

@get: Rule
val coroutineTestRule = CoroutineTestRule()

private val bookmarkRepository = TestBookmarkRepository()
private val recentRepository = TestRecentRepository()

private lateinit var viewModel: BookmarkViewModel

@Before
fun setup() {
viewModel = BookmarkViewModel(bookmarkRepository,recentRepository)
}

@Test
fun `Given a Unit when Init intent is handled then state is updated`() = runTest {
viewModel.handleIntent(BookmarkUiIntent.Init)

viewModel.uiState.test {
val state = awaitItem()
assert(state.files.isEmpty())
}
}

@Test
fun `Given a file when ClickFile intent is handled then navigate to pdf`() = runTest {
val file = PDF_DUMMY

viewModel.handleIntent(BookmarkUiIntent.ClickFile(file))

viewModel.sideEffect.test {
awaitItem().also {
assert(it is BookmarkSideEffect.NavigateToPdf)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아래와 같이 작성하면 스마트 캐스팅을 활용할 수 있습니다.

val effect = awaitItem()
assert(effect is BookmarkSideEffect.NavigateToPdf)
assert(effect.path == file.path)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

require를 활용한 방법은 어떤가요

require(this is BookmarkSideEffect.NavigateToPdf)
assert(path == file.path)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트 코드에서 require는 적합하지 않습니다.
require의 용도는 입력값에 대한 사전 조건 확인을 의미합니다. 반면 assert는 실행 결과가 기대한 바와 맞는지에 대한 검증입니다.
테스트 코드는 동작한 코드의 결과물에 대한 "검증" 이 목적이므로 assert가 사용사례에 맞습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

전 assert로 왜 스마트 캐스팅이 안되죠,,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

음? 그럼 혹시 assertTrue(effect is BookmarkSideEffect.NavigateToPdf) 로 해보시겠어요?
그래도 캐스팅이 안된다면 require를 사용하지 않은 기존의 형태로 하셔도 됩니다.

assert((it as BookmarkSideEffect.NavigateToPdf).path == file.path)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assertEquals를 사용하면 의미를 더 정확하게 표현할 수 있습니다.
값 검증을 위한 다양한 assert가 있으니 활용해보면 좋겠습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다음 PR에서 수정했습니다

}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import kr.co.model.ExploreSideEffect
import kr.co.model.ExploreUiIntent
import kr.co.model.FileInfo
import kr.co.model.FileInfo.Type.PDF
import kr.co.testing.dummy.FOLDER_DUMMY
import kr.co.testing.dummy.PDF_DUMMY
import kr.co.testing.repository.TestRecentRepository
import kr.co.testing.rule.CoroutineTestRule
import kr.co.util.FileManager
Expand Down Expand Up @@ -93,28 +95,4 @@ class ExploreViewModelTest {
}
}
}

companion object {
val PDF_DUMMY = FileInfo(
name = "DUMMY.pdf",
path = "",
type = PDF,
isDirectory = false,
isHidden = false,
size = 0,
createdAt = LocalDateTime.now(),
lastModified = LocalDateTime.now()
)

val FOLDER_DUMMY = FileInfo(
name = "DUMMY",
path = "",
type = PDF,
isDirectory = true,
isHidden = false,
size = 0,
createdAt = LocalDateTime.now(),
lastModified = LocalDateTime.now()
)
}
}
Loading