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

如何移除单元测试中冗余的双感叹号(!!)非空断言?

Kotlin 单元测试非空断言智能转换问题解决方案

问题原因

JVM 平台普通 assert 语句默认仅在开启 -ea 断言参数的运行环境下生效,正式编译打包时会被直接剥离,因此 Kotlin 编译器不会将 assert(password != null) 的判断结果作为非空依据,无法触发非空智能转换。

优化方案

方案1:使用 Kotlin 标准库非空校验函数

checkNotNull、requireNotNull 等标准库函数自带 Kotlin 契约声明,校验通过后编译器会自动将变量识别为非空,无需额外添加非空断言:

@Test
public fun `password is not null and has the exact length between 1 and 64`() {
    repeat(64) {
        mockPasswordLengthPreferenceBy(it + 1)
        val password = passwordGenerator.generatePassword()

        val nonNullPassword = checkNotNull(password)
        assertTrue(nonNullPassword.length == it + 1)
        assertTrue(passwordGenerator.validatePassword(nonNullPassword))
    }
}

注:原代码存在长度校验逻辑问题,你设置的密码长度为it+1,正确校验逻辑应为判断长度等于it+1而非it。

方案2:使用带契约支持的测试断言

新版 kotlin-test 库提供的 assertNotNull 断言已添加契约支持,校验通过后可直接触发非空智能转换:

@Test
public fun `password is not null and has the exact length between 1 and 64`() {
    repeat(64) {
        mockPasswordLengthPreferenceBy(it + 1)
        val password = passwordGenerator.generatePassword()

        assertNotNull(password)
        assertTrue(password.length == it + 1)
        assertTrue(passwordGenerator.validatePassword(password))
    }
}

如果使用的是不支持契约的旧版本断言,可直接在变量声明时添加兜底逻辑触发智能转换:

val password = passwordGenerator.generatePassword() ?: error("生成密码不可为空")

方案3:使用安全调用+作用域函数

仅需要在非空场景下执行后续逻辑时,可直接使用安全调用搭配 let 函数,无需额外校验:

@Test
public fun `password is not null and has the exact length between 1 and 64`() {
    repeat(64) {
        mockPasswordLengthPreferenceBy(it + 1)
        passwordGenerator.generatePassword()?.let { password ->
            assertTrue(password.length == it + 1)
            assertTrue(passwordGenerator.validatePassword(password))
        } ?: fail("生成密码不可为空")
    }
}

内容的提问来源于stack exchange,提问作者René Jörg Spies

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 03:06:03