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

Android中TextUtils.isDigitsOnly未Mock报错,求测试Mock方案

解决Android单元测试中TextUtils.isDigitsOnly未Mock的问题

你在实现输入验证逻辑时,通过Kotlin扩展调用了Android框架的TextUtils.isDigitsOnly方法,单元测试时出现以下错误:

Method isDigitsOnly in android.text.TextUtils not mocked

直接Mock TextUtils实例无效,因为isDigitsOnly是静态方法,Mockito默认无法Mock静态方法,且Mock实例对静态方法调用不起作用。以下是三种可行的解决方案:

方案1:封装Android框架依赖(推荐,符合依赖倒置原则)

核心思路是将Android框架的调用封装为独立接口,让验证类依赖抽象接口而非具体的Android工具类,测试时即可轻松Mock接口实现。

步骤1:创建封装接口与实现

// 抽象数字验证逻辑的接口
interface StringValidator {
    fun isDigitsOnly(input: String): Boolean
}

// 生产环境实现,调用Android的TextUtils
class AndroidStringValidator : StringValidator {
    override fun isDigitsOnly(input: String): Boolean {
        return TextUtils.isDigitsOnly(input)
    }
}

步骤2:修改验证类,注入接口依赖

class ValidationInputImpl(
    private val stringValidator: StringValidator = AndroidStringValidator()
) {
    fun isDigitsOnly(size: String): Boolean {
        return !size.trim().let { stringValidator.isDigitsOnly(it) }
    }

    operator fun invoke(input: String): ValidationResult {
        return if (isDigitsOnly(input)) {
            ValidationResult.Failure
        } else {
            ValidationResult.Success
        }
    }
}

// 假设你的ValidationResult定义
sealed class ValidationResult {
    object Success : ValidationResult()
    object Failure : ValidationResult()
}

步骤3:测试类中Mock接口

@RunWith(MockitoJUnitRunner::class)
class ValidationInputImplTest {

    @Mock
    private lateinit var mockStringValidator: StringValidator

    private lateinit var validationInputImpl: ValidationInputImpl

    @Before
    fun setUp() {
        validationInputImpl = ValidationInputImpl(mockStringValidator)
    }

    @Test
    fun `contains only digits returns success`() {
        val input = "66"
        `when`(mockStringValidator.isDigitsOnly(input.trim())).thenReturn(true)
        
        val result = validationInputImpl(input)
        assertTrue(result is ValidationResult.Success)
    }

    @Test
    fun `contains non-digit characters returns failure`() {
        val input = "66a"
        `when`(mockStringValidator.isDigitsOnly(input.trim())).thenReturn(false)
        
        val result = validationInputImpl(input)
        assertTrue(result is ValidationResult.Failure)
    }
}

方案2:使用PowerMockMock静态方法

如果不想修改原有代码结构,可以用PowerMock直接Mock静态方法,需额外配置依赖:

步骤1:添加PowerMock依赖

在Module级别的build.gradle中添加:

testImplementation "org.powermock:powermock-module-junit4:2.0.9"
testImplementation "org.powermock:powermock-api-mockito2:2.0.9"

步骤2:修改测试类

@RunWith(PowerMockRunner::class)
@PrepareForTest(TextUtils::class) // 指定要Mock的静态类
class ValidationInputImplTest {

    private lateinit var validationInputImpl: ValidationInputImpl

    @Before
    fun setUp() {
        validationInputImpl = ValidationInputImpl()
        PowerMockito.mockStatic(TextUtils::class.java)
    }

    @Test
    fun `contains only digits returns success`() {
        val input = "66"
        PowerMockito.`when`(TextUtils.isDigitsOnly(input.trim())).thenReturn(true)
        
        val result = validationInputImpl(input)
        assertTrue(result is ValidationResult.Success)
    }
}

方案3:纯Kotlin实现数字验证(无需依赖Android框架)

如果验证逻辑简单,可直接用纯Kotlin实现数字判断,完全脱离Android框架,测试无需Mock:

修改验证类逻辑:

override fun isDigitsOnly(size: String): Boolean {
    return !size.trim().all { it.isDigit() }
}

对应的单元测试:

@RunWith(MockitoJUnitRunner::class)
class ValidationInputImplTest {

    private lateinit var validationInputImpl: ValidationInputImpl

    @Before
    fun setUp() {
        validationInputImpl = ValidationInputImpl()
    }

    @Test
    fun `contains only digits returns success`() {
        val input = "66"
        val result = validationInputImpl(input)
        assertTrue(result is ValidationResult.Success)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 00:32:52