diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListFragment.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListFragment.kt index f07c2a518..69a5d19fb 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListFragment.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListFragment.kt @@ -10,6 +10,7 @@ import com.festago.festago.R import com.festago.festago.databinding.FragmentFestivalListBinding import com.festago.festago.presentation.ui.home.ticketlist.TicketListFragment import com.festago.festago.presentation.ui.ticketreserve.TicketReserveActivity +import com.festago.festago.presentation.util.repeatOnStarted import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -38,12 +39,16 @@ class FestivalListFragment : Fragment(R.layout.fragment_festival_list) { } private fun initObserve() { - vm.uiState.observe(viewLifecycleOwner) { - binding.uiState = it - updateUi(it) + repeatOnStarted(viewLifecycleOwner) { + vm.uiState.collect { + binding.uiState = it + updateUi(it) + } } - vm.event.observe(viewLifecycleOwner) { - handleEvent(it) + repeatOnStarted(viewLifecycleOwner) { + vm.event.collect { + handleEvent(it) + } } } diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListViewModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListViewModel.kt index ed586fc36..78d86dc88 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListViewModel.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListViewModel.kt @@ -1,16 +1,18 @@ package com.festago.festago.presentation.ui.home.festivallist -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.festago.festago.analytics.AnalyticsHelper import com.festago.festago.analytics.logNetworkFailure import com.festago.festago.presentation.ui.home.festivallist.FestivalListEvent.ShowTicketReserve -import com.festago.festago.presentation.util.MutableSingleLiveData -import com.festago.festago.presentation.util.SingleLiveData import com.festago.festago.repository.FestivalRepository import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import javax.inject.Inject @@ -19,11 +21,12 @@ class FestivalListViewModel @Inject constructor( private val festivalRepository: FestivalRepository, private val analyticsHelper: AnalyticsHelper, ) : ViewModel() { - private val _uiState = MutableLiveData(FestivalListUiState.Loading) - val uiState: LiveData = _uiState - private val _event = MutableSingleLiveData() - val event: SingleLiveData = _event + private val _uiState = MutableStateFlow(FestivalListUiState.Loading) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _event = MutableSharedFlow() + val event: SharedFlow = _event.asSharedFlow() fun loadFestivals() { viewModelScope.launch { @@ -49,7 +52,9 @@ class FestivalListViewModel @Inject constructor( } fun showTicketReserve(festivalId: Long) { - _event.setValue(ShowTicketReserve(festivalId)) + viewModelScope.launch { + _event.emit(ShowTicketReserve(festivalId)) + } } companion object { diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageFragment.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageFragment.kt index 13d8f1afe..ed540d213 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageFragment.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageFragment.kt @@ -13,6 +13,7 @@ import com.festago.festago.presentation.ui.home.HomeActivity import com.festago.festago.presentation.ui.selectschool.SelectSchoolActivity import com.festago.festago.presentation.ui.signin.SignInActivity import com.festago.festago.presentation.ui.tickethistory.TicketHistoryActivity +import com.festago.festago.presentation.util.repeatOnStarted import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -40,26 +41,38 @@ class MyPageFragment : Fragment(R.layout.fragment_my_page) { } private fun initObserve() { - vm.uiState.observe(viewLifecycleOwner) { uiState -> - binding.uiState = uiState - when (uiState) { - is MyPageUiState.Loading, is MyPageUiState.Error -> Unit - - is MyPageUiState.Success -> handleSuccess(uiState) + repeatOnStarted(viewLifecycleOwner) { + vm.uiState.collect { uiState -> + handleUiState(uiState) } - binding.srlMyPage.isRefreshing = false } - vm.event.observe(viewLifecycleOwner) { event -> - when (event) { - is MyPageEvent.ShowSignIn -> handleShowSignInEvent() - is MyPageEvent.SignOutSuccess -> handleSignOutSuccessEvent() - is MyPageEvent.DeleteAccountSuccess -> handleDeleteAccountSuccess() - is MyPageEvent.ShowTicketHistory -> handleShowTicketHistory() - is MyPageEvent.ShowConfirmDelete -> handleShowConfirmDelete() + repeatOnStarted(viewLifecycleOwner) { + vm.event.collect { event -> + handleEvent(event) } } } + private fun handleUiState(uiState: MyPageUiState) { + binding.uiState = uiState + when (uiState) { + is MyPageUiState.Loading, is MyPageUiState.Error -> Unit + + is MyPageUiState.Success -> handleSuccess(uiState) + } + binding.srlMyPage.isRefreshing = false + } + + private fun handleEvent(event: MyPageEvent) { + when (event) { + is MyPageEvent.ShowSignIn -> handleShowSignInEvent() + is MyPageEvent.SignOutSuccess -> handleSignOutSuccessEvent() + is MyPageEvent.DeleteAccountSuccess -> handleDeleteAccountSuccess() + is MyPageEvent.ShowTicketHistory -> handleShowTicketHistory() + is MyPageEvent.ShowConfirmDelete -> handleShowConfirmDelete() + } + } + private fun handleShowSignInEvent() { startActivity(SignInActivity.getIntent(requireContext())) } diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageViewModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageViewModel.kt index 27ea3319e..a9373d4c6 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageViewModel.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageViewModel.kt @@ -1,18 +1,20 @@ package com.festago.festago.presentation.ui.home.mypage -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.festago.festago.analytics.AnalyticsHelper import com.festago.festago.analytics.logNetworkFailure -import com.festago.festago.presentation.util.MutableSingleLiveData -import com.festago.festago.presentation.util.SingleLiveData import com.festago.festago.repository.AuthRepository import com.festago.festago.repository.TicketRepository import com.festago.festago.repository.UserRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.async +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import javax.inject.Inject @@ -24,16 +26,18 @@ class MyPageViewModel @Inject constructor( private val analyticsHelper: AnalyticsHelper, ) : ViewModel() { - private val _uiState = MutableLiveData(MyPageUiState.Loading) - val uiState: LiveData = _uiState + private val _uiState = MutableStateFlow(MyPageUiState.Loading) + val uiState: StateFlow = _uiState.asStateFlow() - private val _event = MutableSingleLiveData() - val event: SingleLiveData = _event + private val _event = MutableSharedFlow() + val event: SharedFlow = _event.asSharedFlow() fun loadUserInfo() { if (!authRepository.isSigned) { - _event.setValue(MyPageEvent.ShowSignIn) - _uiState.value = MyPageUiState.Error + viewModelScope.launch { + _event.emit(MyPageEvent.ShowSignIn) + _uiState.value = MyPageUiState.Error + } return } viewModelScope.launch { @@ -59,7 +63,7 @@ class MyPageViewModel @Inject constructor( viewModelScope.launch { authRepository.signOut() .onSuccess { - _event.setValue(MyPageEvent.SignOutSuccess) + _event.emit(MyPageEvent.SignOutSuccess) _uiState.value = MyPageUiState.Error }.onFailure { _uiState.value = MyPageUiState.Error @@ -72,14 +76,16 @@ class MyPageViewModel @Inject constructor( } fun showConfirmDelete() { - _event.setValue(MyPageEvent.ShowConfirmDelete) + viewModelScope.launch { + _event.emit(MyPageEvent.ShowConfirmDelete) + } } fun deleteAccount() { viewModelScope.launch { authRepository.deleteAccount() .onSuccess { - _event.setValue(MyPageEvent.DeleteAccountSuccess) + _event.emit(MyPageEvent.DeleteAccountSuccess) _uiState.value = MyPageUiState.Error }.onFailure { _uiState.value = MyPageUiState.Error @@ -92,7 +98,9 @@ class MyPageViewModel @Inject constructor( } fun showTicketHistory() { - _event.setValue(MyPageEvent.ShowTicketHistory) + viewModelScope.launch { + _event.emit(MyPageEvent.ShowTicketHistory) + } } companion object { diff --git a/android/festago/app/src/test/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListViewModelTest.kt b/android/festago/app/src/test/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListViewModelTest.kt index 95d5e5344..56b5b060b 100644 --- a/android/festago/app/src/test/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListViewModelTest.kt +++ b/android/festago/app/src/test/java/com/festago/festago/presentation/ui/home/festivallist/FestivalListViewModelTest.kt @@ -1,6 +1,6 @@ package com.festago.festago.presentation.ui.home.festivallist -import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import app.cash.turbine.test import com.festago.festago.analytics.AnalyticsHelper import com.festago.festago.model.Festival import com.festago.festago.repository.FestivalRepository @@ -11,16 +11,17 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.delay import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.SoftAssertions import org.junit.After import org.junit.Before -import org.junit.Rule import org.junit.Test import java.time.LocalDate class FestivalListViewModelTest { + private lateinit var vm: FestivalListViewModel private lateinit var festivalRepository: FestivalRepository private lateinit var analyticsHelper: AnalyticsHelper @@ -35,9 +36,6 @@ class FestivalListViewModelTest { ) } - @get:Rule - val instantExecutorRule = InstantTaskExecutorRule() - @OptIn(ExperimentalCoroutinesApi::class) @Before fun setUp() { @@ -53,14 +51,18 @@ class FestivalListViewModelTest { Dispatchers.resetMain() } - @Test - fun `축제 목록 받아오기에 성공하면 성공 상태이고 축제 목록을 반환한다`() { - // given + private fun `축제 목록 요청 결과가 다음과 같을 때`(result: Result>) { coEvery { festivalRepository.loadFestivals() } answers { - Result.success(fakeFestivals) + result } + } + + @Test + fun `축제 목록 받아오기에 성공하면 성공 상태이고 축제 목록을 반환한다`() { + // given + `축제 목록 요청 결과가 다음과 같을 때`(Result.success(fakeFestivals)) // when vm.loadFestivals() @@ -70,9 +72,9 @@ class FestivalListViewModelTest { assertThat(vm.uiState.value).isInstanceOf(FestivalListUiState.Success::class.java) // and - assertThat(vm.uiState.value?.shouldShowSuccess).isEqualTo(true) - assertThat(vm.uiState.value?.shouldShowLoading).isEqualTo(false) - assertThat(vm.uiState.value?.shouldShowError).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowSuccess).isEqualTo(true) + assertThat(vm.uiState.value.shouldShowLoading).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowError).isEqualTo(false) // and val actual = (vm.uiState.value as FestivalListUiState.Success).festivals @@ -85,11 +87,7 @@ class FestivalListViewModelTest { @Test fun `축제 목록 받아오기에 실패하면 에러 상태다`() { // given - coEvery { - festivalRepository.loadFestivals() - } answers { - Result.failure(Exception()) - } + `축제 목록 요청 결과가 다음과 같을 때`(Result.failure(Exception())) // when vm.loadFestivals() @@ -99,9 +97,9 @@ class FestivalListViewModelTest { assertThat(vm.uiState.value).isInstanceOf(FestivalListUiState.Error::class.java) // and - assertThat(vm.uiState.value?.shouldShowSuccess).isEqualTo(false) - assertThat(vm.uiState.value?.shouldShowLoading).isEqualTo(false) - assertThat(vm.uiState.value?.shouldShowError).isEqualTo(true) + assertThat(vm.uiState.value.shouldShowSuccess).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowLoading).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowError).isEqualTo(true) } softly.assertAll() } @@ -124,21 +122,24 @@ class FestivalListViewModelTest { assertThat(vm.uiState.value).isInstanceOf(FestivalListUiState.Loading::class.java) // and - assertThat(vm.uiState.value?.shouldShowSuccess).isEqualTo(false) - assertThat(vm.uiState.value?.shouldShowLoading).isEqualTo(true) - assertThat(vm.uiState.value?.shouldShowError).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowSuccess).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowLoading).isEqualTo(true) + assertThat(vm.uiState.value.shouldShowError).isEqualTo(false) } softly.assertAll() } @Test - fun `티켓 예매를 열면 티켓 예매 열기 이벤트가 발생한다`() { - // when - val fakeFestivalId = 1L - vm.showTicketReserve(fakeFestivalId) + fun `티켓 예매를 열면 티켓 예매 열기 이벤트가 발생한다`() = runTest { - // then - assertThat(vm.event.getValue()).isInstanceOf(FestivalListEvent.ShowTicketReserve::class.java) + vm.event.test { + // when + val fakeFestivalId = 1L + vm.showTicketReserve(fakeFestivalId) + + // then + assertThat(awaitItem()).isExactlyInstanceOf(FestivalListEvent.ShowTicketReserve::class.java) + } } private fun Festival.toUiState() = FestivalItemUiState( diff --git a/android/festago/app/src/test/java/com/festago/festago/presentation/ui/home/mypage/MyPageViewModelTest.kt b/android/festago/app/src/test/java/com/festago/festago/presentation/ui/home/mypage/MyPageViewModelTest.kt index 013d96d33..2eb87bdae 100644 --- a/android/festago/app/src/test/java/com/festago/festago/presentation/ui/home/mypage/MyPageViewModelTest.kt +++ b/android/festago/app/src/test/java/com/festago/festago/presentation/ui/home/mypage/MyPageViewModelTest.kt @@ -1,6 +1,6 @@ package com.festago.festago.presentation.ui.home.mypage -import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import app.cash.turbine.test import com.festago.festago.analytics.AnalyticsHelper import com.festago.festago.model.MemberTicketFestival import com.festago.festago.model.Stage @@ -17,12 +17,12 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.delay import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.SoftAssertions import org.junit.After import org.junit.Before -import org.junit.Rule import org.junit.Test import java.time.LocalDateTime @@ -55,9 +55,6 @@ class MyPageViewModelTest { ), ) - @get:Rule - val instantExecutorRule = InstantTaskExecutorRule() - @OptIn(ExperimentalCoroutinesApi::class) @Before fun setUp() { @@ -75,42 +72,52 @@ class MyPageViewModelTest { Dispatchers.resetMain() } - @Test - fun `로그인 되지 않았다면 로그인 이벤트가 발생한다`() { - // given + private fun `로그인 상태가 다음과 같다`(result: Boolean) { coEvery { authRepository.isSigned } answers { - false + result } - - // when - vm.loadUserInfo() - - // then - assertThat(vm.event.getValue() is MyPageEvent.ShowSignIn).isTrue } - @Test - fun `유저 프로필, 첫번째 티켓 받아오기에 성공하면 성공 상태다`() { - // given + private fun `유저 프로필 요청의 결과가 다음과 같다`(result: Result) { coEvery { userRepository.loadUserProfile() } answers { - Result.success(fakeUserProfile) + result } + } + private fun `과거 예매 내역 요청의 결과가 다음과 같다`(result: Result>) { coEvery { - ticketRepository.loadHistoryTickets(1) + ticketRepository.loadHistoryTickets(any()) } answers { - Result.success(fakeTickets) + result } + } - coEvery { - authRepository.isSigned - } answers { - true + @Test + fun `로그인 되지 않았다면 로그인 이벤트가 발생한다`() = runTest { + // given + `로그인 상태가 다음과 같다`(false) + + vm.event.test { + // when + vm.loadUserInfo() + + // then + assertThat(awaitItem()).isExactlyInstanceOf(MyPageEvent.ShowSignIn::class.java) } + } + + @Test + fun `유저 프로필, 과거 예매 내역 받아오기에 성공하면 성공 상태다`() { + // given + `유저 프로필 요청의 결과가 다음과 같다`(Result.success(fakeUserProfile)) + + `과거 예매 내역 요청의 결과가 다음과 같다`(Result.success(fakeTickets)) + + `로그인 상태가 다음과 같다`(true) // when vm.loadUserInfo() @@ -120,9 +127,9 @@ class MyPageViewModelTest { assertThat(vm.uiState.value).isInstanceOf(MyPageUiState.Success::class.java) // and - assertThat(vm.uiState.value?.shouldShowSuccess).isEqualTo(true) - assertThat(vm.uiState.value?.shouldShowLoading).isEqualTo(false) - assertThat(vm.uiState.value?.shouldShowError).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowSuccess).isEqualTo(true) + assertThat(vm.uiState.value.shouldShowLoading).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowError).isEqualTo(false) // and val actualUserProfile = (vm.uiState.value as MyPageUiState.Success).userProfile @@ -136,13 +143,9 @@ class MyPageViewModelTest { } @Test - fun `유저 프로필 받아오기에 성공하고, 첫번째 티켓을 받아오는 중이면 로딩 상태이다`() { + fun `유저 프로필 받아오기에 성공하고, 과거 예매 내역을 받아오는 중이면 로딩 상태이다`() { // given - coEvery { - userRepository.loadUserProfile() - } answers { - Result.success(fakeUserProfile) - } + `유저 프로필 요청의 결과가 다음과 같다`(Result.success(fakeUserProfile)) coEvery { ticketRepository.loadHistoryTickets(1) @@ -151,11 +154,7 @@ class MyPageViewModelTest { Result.success(fakeTickets) } - coEvery { - authRepository.isSigned - } answers { - true - } + `로그인 상태가 다음과 같다`(true) // when vm.loadUserInfo() @@ -165,9 +164,9 @@ class MyPageViewModelTest { assertThat(vm.uiState.value).isInstanceOf(MyPageUiState.Loading::class.java) // and - assertThat(vm.uiState.value?.shouldShowSuccess).isEqualTo(false) - assertThat(vm.uiState.value?.shouldShowLoading).isEqualTo(true) - assertThat(vm.uiState.value?.shouldShowError).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowSuccess).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowLoading).isEqualTo(true) + assertThat(vm.uiState.value.shouldShowError).isEqualTo(false) } softly.assertAll() } @@ -175,23 +174,11 @@ class MyPageViewModelTest { @Test fun `유저 프로필 받아오기 실패하면 에러 상태다`() { // given - coEvery { - userRepository.loadUserProfile() - } answers { - Result.failure(Exception()) - } + `유저 프로필 요청의 결과가 다음과 같다`(Result.failure(Exception())) - coEvery { - ticketRepository.loadHistoryTickets(1) - } answers { - Result.success(fakeTickets) - } + `과거 예매 내역 요청의 결과가 다음과 같다`(Result.success(fakeTickets)) - coEvery { - authRepository.isSigned - } answers { - true - } + `로그인 상태가 다음과 같다`(true) // when vm.loadUserInfo() @@ -201,33 +188,21 @@ class MyPageViewModelTest { assertThat(vm.uiState.value).isInstanceOf(MyPageUiState.Error::class.java) // and - assertThat(vm.uiState.value?.shouldShowSuccess).isEqualTo(false) - assertThat(vm.uiState.value?.shouldShowLoading).isEqualTo(false) - assertThat(vm.uiState.value?.shouldShowError).isEqualTo(true) + assertThat(vm.uiState.value.shouldShowSuccess).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowLoading).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowError).isEqualTo(true) } softly.assertAll() } @Test - fun `첫번째 티켓 받아오기에 실패하면 에러 상태다`() { + fun `과거 예매 내역 받아오기에 실패하면 에러 상태다`() { // given - coEvery { - userRepository.loadUserProfile() - } answers { - Result.success(fakeUserProfile) - } + `유저 프로필 요청의 결과가 다음과 같다`(Result.success(fakeUserProfile)) - coEvery { - ticketRepository.loadHistoryTickets(1) - } answers { - Result.failure(Exception()) - } + `과거 예매 내역 요청의 결과가 다음과 같다`(Result.failure(Exception())) - coEvery { - authRepository.isSigned - } answers { - true - } + `로그인 상태가 다음과 같다`(true) // when vm.loadUserInfo() @@ -237,15 +212,15 @@ class MyPageViewModelTest { assertThat(vm.uiState.value).isInstanceOf(MyPageUiState.Error::class.java) // and - assertThat(vm.uiState.value?.shouldShowSuccess).isEqualTo(false) - assertThat(vm.uiState.value?.shouldShowLoading).isEqualTo(false) - assertThat(vm.uiState.value?.shouldShowError).isEqualTo(true) + assertThat(vm.uiState.value.shouldShowSuccess).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowLoading).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowError).isEqualTo(true) } softly.assertAll() } @Test - fun `로그아웃에 성공하면 SignOutSuccess 이벤트가 발생하고 에러 상태이다`() { + fun `로그아웃에 성공하면 SignOutSuccess 이벤트가 발생하고 에러 상태이다`() = runTest { // given coEvery { authRepository.signOut() @@ -253,33 +228,37 @@ class MyPageViewModelTest { Result.success(Unit) } - // when - vm.signOut() - - // then - val softly = SoftAssertions().apply { - assertThat(vm.event.getValue() is MyPageEvent.SignOutSuccess).isTrue - assertThat(vm.uiState.value is MyPageUiState.Error).isTrue - - // and - assertThat(vm.uiState.value?.shouldShowSuccess).isEqualTo(false) - assertThat(vm.uiState.value?.shouldShowLoading).isEqualTo(false) - assertThat(vm.uiState.value?.shouldShowError).isEqualTo(true) + vm.event.test { + // when + vm.signOut() + + // then + val softly = SoftAssertions().apply { + assertThat(awaitItem()).isExactlyInstanceOf(MyPageEvent.SignOutSuccess::class.java) + assertThat(vm.uiState.value is MyPageUiState.Error).isTrue + + // and + assertThat(vm.uiState.value.shouldShowSuccess).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowLoading).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowError).isEqualTo(true) + } + softly.assertAll() } - softly.assertAll() } @Test - fun `회원탈퇴 확인 이벤트가 발생한다`() { - // when - vm.showConfirmDelete() + fun `회원탈퇴 확인 이벤트가 발생한다`() = runTest { + vm.event.test { + // when + vm.showConfirmDelete() - // then - assertThat(vm.event.getValue() is MyPageEvent.ShowConfirmDelete).isTrue + // then + assertThat(awaitItem()).isExactlyInstanceOf(MyPageEvent.ShowConfirmDelete::class.java) + } } @Test - fun `회원 탈퇴에 성공하면 DeleteAccountSuccess 이벤트가 발생하고 에러상태다`() { + fun `회원 탈퇴에 성공하면 DeleteAccountSuccess 이벤트가 발생하고 에러상태다`() = runTest { // given coEvery { authRepository.deleteAccount() @@ -287,19 +266,21 @@ class MyPageViewModelTest { Result.success(Unit) } - // when - vm.deleteAccount() - - // then - val softly = SoftAssertions().apply { - assertThat(vm.event.getValue() is MyPageEvent.DeleteAccountSuccess).isTrue - assertThat(vm.uiState.value is MyPageUiState.Error).isTrue - - // and - assertThat(vm.uiState.value?.shouldShowSuccess).isEqualTo(false) - assertThat(vm.uiState.value?.shouldShowLoading).isEqualTo(false) - assertThat(vm.uiState.value?.shouldShowError).isEqualTo(true) + vm.event.test { + // when + vm.deleteAccount() + + // then + val softly = SoftAssertions().apply { + assertThat(awaitItem()).isExactlyInstanceOf(MyPageEvent.DeleteAccountSuccess::class.java) + assertThat(vm.uiState.value is MyPageUiState.Error).isTrue + + // and + assertThat(vm.uiState.value.shouldShowSuccess).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowLoading).isEqualTo(false) + assertThat(vm.uiState.value.shouldShowError).isEqualTo(true) + } + softly.assertAll() } - softly.assertAll() } } diff --git a/android/festago/app/src/test/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolViewModelTest.kt b/android/festago/app/src/test/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolViewModelTest.kt index a9b59129b..fc884afee 100644 --- a/android/festago/app/src/test/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolViewModelTest.kt +++ b/android/festago/app/src/test/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolViewModelTest.kt @@ -121,7 +121,6 @@ class SelectSchoolViewModelTest { // then assertThat(awaitItem()).isExactlyInstanceOf(SelectSchoolEvent.ShowStudentVerification::class.java) - cancelAndIgnoreRemainingEvents() } }