Fix AppBatteryPreferenceTest flaky

Bug: 335887683
Test: unit test
Change-Id: I5a1753835d2d47712ea249081c9a77c455eb3291
This commit is contained in:
Chaohui Wang
2024-04-23 17:53:25 +08:00
parent 174acf5c67
commit 23c66d1278
2 changed files with 40 additions and 33 deletions

View File

@@ -24,6 +24,7 @@
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" /> <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
<uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
<uses-permission android:name="com.android.settings.BATTERY_DATA" />
<application android:debuggable="true"> <application android:debuggable="true">
<provider android:name="com.android.settings.slices.SettingsSliceProvider" <provider android:name="com.android.settings.slices.SettingsSliceProvider"

View File

@@ -20,13 +20,14 @@ import android.content.Context
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotDisplayed import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertIsNotEnabled import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.hasTextExactly import androidx.compose.ui.test.hasTextExactly
import androidx.compose.ui.test.isEnabled
import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performClick
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
@@ -36,18 +37,23 @@ import com.android.settings.R
import com.android.settings.fuelgauge.AdvancedPowerUsageDetail import com.android.settings.fuelgauge.AdvancedPowerUsageDetail
import com.android.settings.fuelgauge.batteryusage.BatteryChartPreferenceController import com.android.settings.fuelgauge.batteryusage.BatteryChartPreferenceController
import com.android.settings.fuelgauge.batteryusage.BatteryDiffEntry import com.android.settings.fuelgauge.batteryusage.BatteryDiffEntry
import com.android.settingslib.spa.testutils.delay
import com.android.settingslib.spaprivileged.model.app.userId import com.android.settingslib.spaprivileged.model.app.userId
import kotlinx.coroutines.runBlocking
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mockito.mock
import org.mockito.MockitoSession import org.mockito.MockitoSession
import org.mockito.Spy import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.stub
import org.mockito.kotlin.whenever
import org.mockito.quality.Strictness import org.mockito.quality.Strictness
import org.mockito.Mockito.`when` as whenever
@OptIn(ExperimentalTestApi::class)
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class AppBatteryPreferenceTest { class AppBatteryPreferenceTest {
@get:Rule @get:Rule
@@ -55,29 +61,28 @@ class AppBatteryPreferenceTest {
private lateinit var mockSession: MockitoSession private lateinit var mockSession: MockitoSession
@Spy private val context: Context = spy(ApplicationProvider.getApplicationContext()) {}
private val context: Context = ApplicationProvider.getApplicationContext()
@Spy private val resources = spy(context.resources) {
private val resources = context.resources on { getBoolean(R.bool.config_show_app_info_settings_battery) } doReturn true
}
@Before @Before
fun setUp() { fun setUp() {
mockSession = ExtendedMockito.mockitoSession() mockSession = ExtendedMockito.mockitoSession()
.initMocks(this)
.mockStatic(BatteryChartPreferenceController::class.java) .mockStatic(BatteryChartPreferenceController::class.java)
.mockStatic(AdvancedPowerUsageDetail::class.java) .mockStatic(AdvancedPowerUsageDetail::class.java)
.strictness(Strictness.LENIENT) .strictness(Strictness.LENIENT)
.startMocking() .startMocking()
whenever(context.resources).thenReturn(resources) whenever(context.resources).thenReturn(resources)
whenever(resources.getBoolean(R.bool.config_show_app_info_settings_battery))
.thenReturn(true)
} }
private fun mockBatteryDiffEntry(batteryDiffEntry: BatteryDiffEntry?) { private fun mockBatteryDiffEntry(batteryDiffEntry: BatteryDiffEntry?) {
whenever(BatteryChartPreferenceController.getAppBatteryUsageData( whenever(
context, PACKAGE_NAME, APP.userId BatteryChartPreferenceController.getAppBatteryUsageData(
)).thenReturn(batteryDiffEntry) context, PACKAGE_NAME, APP.userId
)
).thenReturn(batteryDiffEntry)
} }
@After @After
@@ -87,8 +92,9 @@ class AppBatteryPreferenceTest {
@Test @Test
fun whenConfigIsFalse_notDisplayed() { fun whenConfigIsFalse_notDisplayed() {
whenever(resources.getBoolean(R.bool.config_show_app_info_settings_battery)) resources.stub {
.thenReturn(false) on { getBoolean(R.bool.config_show_app_info_settings_battery) } doReturn false
}
setContent() setContent()
@@ -112,47 +118,47 @@ class AppBatteryPreferenceTest {
setContent() setContent()
composeTestRule.onNode( composeTestRule.waitUntilExactlyOneExists(
hasTextExactly( hasTextExactly(
context.getString(R.string.battery_details_title), context.getString(R.string.battery_details_title),
context.getString(R.string.no_battery_summary), context.getString(R.string.no_battery_summary),
), ) and isEnabled(),
).assertIsDisplayed().assertIsEnabled() )
} }
@Test @Test
fun noConsumePower() { fun noConsumePower() {
val batteryDiffEntry = mock(BatteryDiffEntry::class.java).apply { val batteryDiffEntry = mock<BatteryDiffEntry>().apply { mConsumePower = 0.0 }
mConsumePower = 0.0
}
mockBatteryDiffEntry(batteryDiffEntry) mockBatteryDiffEntry(batteryDiffEntry)
setContent() setContent()
composeTestRule.onNodeWithText(context.getString(R.string.no_battery_summary)) composeTestRule.waitUntilExactlyOneExists(
.assertIsDisplayed() hasText(context.getString(R.string.no_battery_summary))
)
} }
@Test @Test
fun hasConsumePower() { fun hasConsumePower() {
val batteryDiffEntry = mock(BatteryDiffEntry::class.java).apply { val batteryDiffEntry = mock<BatteryDiffEntry> {
mConsumePower = 12.3 on { percentage } doReturn 45.6
} }.apply { mConsumePower = 12.3 }
whenever(batteryDiffEntry.percentage).thenReturn(45.6)
mockBatteryDiffEntry(batteryDiffEntry) mockBatteryDiffEntry(batteryDiffEntry)
setContent() setContent()
composeTestRule.onNodeWithText("46% use since last full charge").assertIsDisplayed() composeTestRule.waitUntilExactlyOneExists(hasText("46% use since last full charge"))
} }
@Test @Test
fun whenClick_openDetailsPage() { fun whenClick_openDetailsPage() {
val batteryDiffEntry = mock(BatteryDiffEntry::class.java) val batteryDiffEntry = mock<BatteryDiffEntry> {
whenever(batteryDiffEntry.percentage).thenReturn(10.0) on { percentage } doReturn 10.0
}.apply { mConsumePower = 12.3 }
mockBatteryDiffEntry(batteryDiffEntry) mockBatteryDiffEntry(batteryDiffEntry)
setContent() setContent()
composeTestRule.waitUntilExactlyOneExists(hasText("10% use since last full charge"))
composeTestRule.onRoot().performClick() composeTestRule.onRoot().performClick()
ExtendedMockito.verify { ExtendedMockito.verify {
@@ -178,7 +184,7 @@ class AppBatteryPreferenceTest {
} }
private companion object { private companion object {
const val PACKAGE_NAME = "packageName" const val PACKAGE_NAME = "package.name"
const val UID = 123 const val UID = 123
val APP = ApplicationInfo().apply { val APP = ApplicationInfo().apply {
packageName = PACKAGE_NAME packageName = PACKAGE_NAME