Clean-up FooterActionsViewModelTest
This CL cleans up FooterActionsViewModelTest and FooterActionsTestUtils by making sure that the same TestCoroutineScheduler is used by all TestDispatchers, and by using the new collectLastValue(Flow) API instead of manually collecting each Flow. Bug: 242040009 Test: atest FooterActionsViewModelTest Change-Id: Ia3b1ae8fba05c2ed9cf3a46d3cc7546161092f42
This commit is contained in:
@@ -41,6 +41,7 @@ import com.android.systemui.util.mockito.eq
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.nullable
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.test.TestCoroutineScheduler
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
@@ -55,7 +56,7 @@ class FooterActionsInteractorTest : SysuiTestCase() {
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
utils = FooterActionsTestUtils(context, TestableLooper.get(this))
|
||||
utils = FooterActionsTestUtils(context, TestableLooper.get(this), TestCoroutineScheduler())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
import com.android.systemui.common.shared.model.ContentDescription
|
||||
import com.android.systemui.common.shared.model.Icon
|
||||
import com.android.systemui.coroutines.collectLastValue
|
||||
import com.android.systemui.qs.FakeFgsManagerController
|
||||
import com.android.systemui.qs.QSSecurityFooterUtils
|
||||
import com.android.systemui.qs.footer.FooterActionsTestUtils
|
||||
@@ -44,12 +45,9 @@ import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.nullable
|
||||
import com.android.systemui.util.settings.FakeSettings
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.TestCoroutineScheduler
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
@@ -62,16 +60,20 @@ import org.mockito.Mockito.`when` as whenever
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@RunWithLooper
|
||||
class FooterActionsViewModelTest : SysuiTestCase() {
|
||||
private val testScope = TestScope()
|
||||
private lateinit var utils: FooterActionsTestUtils
|
||||
private val testDispatcher = UnconfinedTestDispatcher(TestCoroutineScheduler())
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
utils = FooterActionsTestUtils(context, TestableLooper.get(this))
|
||||
utils = FooterActionsTestUtils(context, TestableLooper.get(this), testScope.testScheduler)
|
||||
}
|
||||
|
||||
private fun runTest(block: suspend TestScope.() -> Unit) {
|
||||
testScope.runTest(testBody = block)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun settingsButton() = runBlockingTest {
|
||||
fun settingsButton() = runTest {
|
||||
val underTest = utils.footerActionsViewModel(showPowerButton = false)
|
||||
val settings = underTest.settings
|
||||
|
||||
@@ -87,7 +89,7 @@ class FooterActionsViewModelTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun powerButton() = runBlockingTest {
|
||||
fun powerButton() = runTest {
|
||||
// Without power button.
|
||||
val underTestWithoutPower = utils.footerActionsViewModel(showPowerButton = false)
|
||||
assertThat(underTestWithoutPower.power).isNull()
|
||||
@@ -114,7 +116,7 @@ class FooterActionsViewModelTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun userSwitcher() = runBlockingTest {
|
||||
fun userSwitcher() = runTest {
|
||||
val picture: Drawable = mock()
|
||||
val userInfoController = FakeUserInfoController(FakeInfo(picture = picture))
|
||||
val settings = FakeSettings()
|
||||
@@ -135,7 +137,6 @@ class FooterActionsViewModelTest : SysuiTestCase() {
|
||||
showPowerButton = false,
|
||||
footerActionsInteractor =
|
||||
utils.footerActionsInteractor(
|
||||
bgDispatcher = testDispatcher,
|
||||
userSwitcherRepository =
|
||||
utils.userSwitcherRepository(
|
||||
userTracker = userTracker,
|
||||
@@ -143,22 +144,12 @@ class FooterActionsViewModelTest : SysuiTestCase() {
|
||||
userManager = userManager,
|
||||
userInfoController = userInfoController,
|
||||
userSwitcherController = userSwitcherControllerWrapper.controller,
|
||||
bgDispatcher = testDispatcher,
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
// Collect the user switcher into currentUserSwitcher.
|
||||
var currentUserSwitcher: FooterActionsButtonViewModel? = null
|
||||
val job = launch { underTest.userSwitcher.collect { currentUserSwitcher = it } }
|
||||
fun currentUserSwitcher(): FooterActionsButtonViewModel? {
|
||||
// Make sure we finish collecting the current user switcher. This is necessary because
|
||||
// combined flows launch multiple coroutines in the current scope so we need to make
|
||||
// sure we process all coroutines triggered by our flow collection before we make
|
||||
// assertions on the current buttons.
|
||||
advanceUntilIdle()
|
||||
return currentUserSwitcher
|
||||
}
|
||||
val currentUserSwitcher = collectLastValue(underTest.userSwitcher)
|
||||
|
||||
// The user switcher is disabled.
|
||||
assertThat(currentUserSwitcher()).isNull()
|
||||
@@ -203,12 +194,10 @@ class FooterActionsViewModelTest : SysuiTestCase() {
|
||||
// in guest mode.
|
||||
userInfoController.updateInfo { this.picture = mock<UserIconDrawable>() }
|
||||
assertThat(iconTint()).isNull()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun security() = runBlockingTest {
|
||||
fun security() = runTest {
|
||||
val securityController = FakeSecurityController()
|
||||
val qsSecurityFooterUtils = mock<QSSecurityFooterUtils>()
|
||||
|
||||
@@ -224,22 +213,15 @@ class FooterActionsViewModelTest : SysuiTestCase() {
|
||||
footerActionsInteractor =
|
||||
utils.footerActionsInteractor(
|
||||
qsSecurityFooterUtils = qsSecurityFooterUtils,
|
||||
bgDispatcher = testDispatcher,
|
||||
securityRepository =
|
||||
utils.securityRepository(
|
||||
securityController = securityController,
|
||||
bgDispatcher = testDispatcher,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
// Collect the security model into currentSecurity.
|
||||
var currentSecurity: FooterActionsSecurityButtonViewModel? = null
|
||||
val job = launch { underTest.security.collect { currentSecurity = it } }
|
||||
fun currentSecurity(): FooterActionsSecurityButtonViewModel? {
|
||||
advanceUntilIdle()
|
||||
return currentSecurity
|
||||
}
|
||||
val currentSecurity = collectLastValue(underTest.security)
|
||||
|
||||
// By default, we always return a null SecurityButtonConfig.
|
||||
assertThat(currentSecurity()).isNull()
|
||||
@@ -270,12 +252,10 @@ class FooterActionsViewModelTest : SysuiTestCase() {
|
||||
security = currentSecurity()
|
||||
assertThat(security).isNotNull()
|
||||
assertThat(security!!.onClick).isNull()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun foregroundServices() = runBlockingTest {
|
||||
fun foregroundServices() = runTest {
|
||||
val securityController = FakeSecurityController()
|
||||
val fgsManagerController =
|
||||
FakeFgsManagerController(
|
||||
@@ -300,21 +280,14 @@ class FooterActionsViewModelTest : SysuiTestCase() {
|
||||
securityRepository =
|
||||
utils.securityRepository(
|
||||
securityController,
|
||||
bgDispatcher = testDispatcher,
|
||||
),
|
||||
foregroundServicesRepository =
|
||||
utils.foregroundServicesRepository(fgsManagerController),
|
||||
bgDispatcher = testDispatcher,
|
||||
),
|
||||
)
|
||||
|
||||
// Collect the security model into currentSecurity.
|
||||
var currentForegroundServices: FooterActionsForegroundServicesButtonViewModel? = null
|
||||
val job = launch { underTest.foregroundServices.collect { currentForegroundServices = it } }
|
||||
fun currentForegroundServices(): FooterActionsForegroundServicesButtonViewModel? {
|
||||
advanceUntilIdle()
|
||||
return currentForegroundServices
|
||||
}
|
||||
val currentForegroundServices = collectLastValue(underTest.foregroundServices)
|
||||
|
||||
// We don't show the foreground services button if the number of running packages is not
|
||||
// > 1.
|
||||
@@ -356,12 +329,10 @@ class FooterActionsViewModelTest : SysuiTestCase() {
|
||||
}
|
||||
securityController.updateState {}
|
||||
assertThat(currentForegroundServices()?.displayText).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun observeDeviceMonitoringDialogRequests() = runBlockingTest {
|
||||
fun observeDeviceMonitoringDialogRequests() = runTest {
|
||||
val qsSecurityFooterUtils = mock<QSSecurityFooterUtils>()
|
||||
val broadcastDispatcher = mock<BroadcastDispatcher>()
|
||||
|
||||
@@ -390,7 +361,6 @@ class FooterActionsViewModelTest : SysuiTestCase() {
|
||||
utils.footerActionsInteractor(
|
||||
qsSecurityFooterUtils = qsSecurityFooterUtils,
|
||||
broadcastDispatcher = broadcastDispatcher,
|
||||
bgDispatcher = testDispatcher,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -415,7 +385,4 @@ class FooterActionsViewModelTest : SysuiTestCase() {
|
||||
underTest.onVisibilityChangeRequested(visible = true)
|
||||
assertThat(underTest.isVisible.value).isTrue()
|
||||
}
|
||||
|
||||
private fun runBlockingTest(block: suspend TestScope.() -> Unit) =
|
||||
runTest(testDispatcher) { block() }
|
||||
}
|
||||
|
||||
@@ -56,7 +56,8 @@ import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.settings.FakeSettings
|
||||
import com.android.systemui.util.settings.GlobalSettings
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.test.TestCoroutineDispatcher
|
||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||
import kotlinx.coroutines.test.TestCoroutineScheduler
|
||||
|
||||
/**
|
||||
* Util class to create real implementations of the FooterActions repositories, viewModel and
|
||||
@@ -65,6 +66,7 @@ import kotlinx.coroutines.test.TestCoroutineDispatcher
|
||||
class FooterActionsTestUtils(
|
||||
private val context: Context,
|
||||
private val testableLooper: TestableLooper,
|
||||
private val scheduler: TestCoroutineScheduler,
|
||||
) {
|
||||
/** Enable or disable the user switcher in the settings. */
|
||||
fun setUserSwitcherEnabled(settings: GlobalSettings, enabled: Boolean, userId: Int) {
|
||||
@@ -105,7 +107,7 @@ class FooterActionsTestUtils(
|
||||
foregroundServicesRepository: ForegroundServicesRepository = foregroundServicesRepository(),
|
||||
userSwitcherRepository: UserSwitcherRepository = userSwitcherRepository(),
|
||||
broadcastDispatcher: BroadcastDispatcher = mock(),
|
||||
bgDispatcher: CoroutineDispatcher = TestCoroutineDispatcher(),
|
||||
bgDispatcher: CoroutineDispatcher = StandardTestDispatcher(scheduler),
|
||||
): FooterActionsInteractor {
|
||||
return FooterActionsInteractorImpl(
|
||||
activityStarter,
|
||||
@@ -126,7 +128,7 @@ class FooterActionsTestUtils(
|
||||
/** Create a [SecurityRepository] to be used in tests. */
|
||||
fun securityRepository(
|
||||
securityController: SecurityController = FakeSecurityController(),
|
||||
bgDispatcher: CoroutineDispatcher = TestCoroutineDispatcher(),
|
||||
bgDispatcher: CoroutineDispatcher = StandardTestDispatcher(scheduler),
|
||||
): SecurityRepository {
|
||||
return SecurityRepositoryImpl(
|
||||
securityController,
|
||||
@@ -145,7 +147,7 @@ class FooterActionsTestUtils(
|
||||
fun userSwitcherRepository(
|
||||
@Application context: Context = this.context.applicationContext,
|
||||
bgHandler: Handler = Handler(testableLooper.looper),
|
||||
bgDispatcher: CoroutineDispatcher = TestCoroutineDispatcher(),
|
||||
bgDispatcher: CoroutineDispatcher = StandardTestDispatcher(scheduler),
|
||||
userManager: UserManager = mock(),
|
||||
userTracker: UserTracker = FakeUserTracker(),
|
||||
userSwitcherController: UserSwitcherController = mock(),
|
||||
|
||||
Reference in New Issue
Block a user