You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Espresso测试中无需Mock Context让ConnectivityManager指定方法返回false?

解决Espresso测试中让connectivityManager.isActiveNetworkMetered()返回false的方案

我之前在做依赖网络状态的Espresso测试时,也遇到过类似的问题——没法Mock应用上下文,又需要让isActiveNetworkMetered()返回false(也就是模拟非计量的WiFi网络)。这里有几个不用Mock上下文的可行方案:

方案1:通过ADB命令强制设置模拟器网络为WiFi

这是最直接的方法,因为WiFi网络默认是非计量的,只要让模拟器的活跃网络是WiFi,isActiveNetworkMetered()就会自然返回false。你可以在测试执行前手动运行以下ADB命令:

# 设置活跃网络类型为WiFi
adb shell cmd connectivity set-network-type WIFI

如果需要在测试代码里自动执行这个命令,也可以通过Instrumentation调用系统shell:

import androidx.test.platform.app.InstrumentationRegistry
import java.io.BufferedReader
import java.io.InputStreamReader

// 在测试的@Before方法中执行
fun setWifiNetwork() {
    val instrumentation = InstrumentationRegistry.getInstrumentation()
    val process = instrumentation.uiAutomation.executeShellCommand("cmd connectivity set-network-type WIFI")
    BufferedReader(InputStreamReader(process.inputStream)).use { it.readText() }
    process.waitFor()
}

这个方法完全依赖系统命令,不需要修改应用代码,非常适合模拟器环境。

方案2:反射修改ConnectivityManager的内部状态

如果ADB命令在某些场景下受限(比如CI环境权限不足),可以用反射直接修改ConnectivityManager的内部状态,让它认为当前网络是非计量的:

import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import androidx.test.core.app.ApplicationProvider
import java.lang.reflect.Method

fun setNetworkNotMetered() {
    val context = ApplicationProvider.getApplicationContext<Context>()
    val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val activeNetwork = cm.activeNetwork

    // 反射调用系统隐藏的setNetworkMetered方法
    val setMeteredMethod: Method = ConnectivityManager::class.java.getDeclaredMethod(
        "setNetworkMetered",
        Network::class.java,
        Boolean::class.javaPrimitiveType
    )
    setMeteredMethod.isAccessible = true
    setMeteredMethod.invoke(cm, activeNetwork, false)
}

注意:这个方法依赖系统隐藏API,不同Android版本可能存在兼容性差异,测试前需要确认目标版本是否支持该方法。

方案3:自定义测试用的NetworkCallback(进阶)

如果你的应用是通过ConnectivityManager.NetworkCallback监听网络状态的,可以在测试中注册自定义回调,主动发送非计量网络的状态通知:

import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import androidx.test.core.app.ApplicationProvider

fun mockNonMeteredNetwork() {
    val context = ApplicationProvider.getApplicationContext<Context>()
    val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

    // 创建模拟的非计量WiFi网络能力
    val capabilities = NetworkCapabilities.Builder()
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
        .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
        .build()

    // 注册临时回调并发送模拟状态
    val callback = object : ConnectivityManager.NetworkCallback() {}
    cm.registerNetworkCallback(capabilities, callback)

    cm.activeNetwork?.let { network ->
        cm.sendNetworkCapabilities(network, capabilities)
    }
}

这个方法适合应用依赖NetworkCallback处理网络状态的场景,能直接让应用收到非计量网络的通知。


内容的提问来源于stack exchange,提问作者Pineapple

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:06:24