如何使用Espresso和Junit在测试套件之间清除应用数据
问题根因
你当前的代码无法生效有两个核心原因:
- 规则作用域错误:父套件
RegressionTests上的@ClassRule只会在全部子测试套件执行完成后触发一次,不会在每个子套件执行的间隙执行,达不到套件之间清数据的需求 - 执行逻辑错误:
pm clear 包名会直接终止当前应用的所有进程,你的测试代码本身就运行在应用进程中,执行该命令后测试进程直接被杀,后续测试自然无法继续运行
解决方案
方案一:手动清理应用本地数据(推荐)
不需要执行shell命令,直接在代码内删除所有应用持久化数据,不会杀掉测试进程,后续测试可以正常运行。
首先实现通用清理方法:
import android.content.Context import android.webkit.WebView import java.io.File fun clearAllAppData(context: Context) { // 清空所有SharedPreferences File(context.filesDir.parentFile, "shared_prefs").takeIf { it.exists() && it.isDirectory } ?.listFiles()?.forEach { it.delete() } // 删除所有本地数据库 context.databaseList().forEach { context.deleteDatabase(it) } // 清空内部存储目录 context.filesDir.deleteRecursively() // 清空缓存目录 context.cacheDir.deleteRecursively() // 如有使用WebView,同步清空WebView缓存 WebView(context).clearCache(true) }
之后删除父套件RegressionTests里的ExternalResource规则,给每一个子测试套件(AuthenticationTests、AuthenticationInvalidTests、CreateAccountTests等)都添加如下@ClassRule:
import androidx.test.platform.app.InstrumentationRegistry import org.junit.ClassRule import org.junit.rules.ExternalResource class AuthenticationTests { companion object { @ClassRule @JvmField val clearDataRule = object : ExternalResource() { // 建议放在before执行,避免上个套件异常未走到after导致数据残留 override fun before() { val targetContext = InstrumentationRegistry.getInstrumentation().targetContext clearAllAppData(targetContext) } } } // 原有测试用例逻辑 }
这样每个套件执行前都会保证应用处于干净状态,也不会影响后续测试运行。
方案二:需使用pm clear命令的场景
如果有特殊场景必须依赖pm clear执行清理,需要通过UIAutomation执行shell命令,避免直接调用Runtime阻塞进程,执行前需要确保测试应用已申请相关权限:
override fun before() { val context = InstrumentationRegistry.getInstrumentation().targetContext val uiAutomation = InstrumentationRegistry.getInstrumentation().uiAutomation // 执行pm clear命令 uiAutomation.executeShellCommand("pm clear ${context.packageName}").use { // 等待命令执行完成 ParcelFileDescriptor.AutoCloseInputStream(it).readBytes() } }
该方案稳定性低于手动清理,仅作为备选。
内容的提问来源于stack exchange,提问作者George
相关产品推荐
相关产品推荐

