java.lang.NullPointerException 用于 null 安全静态方法中的 null 输入

java.lang.NullPointerException for null input in null safe static method

@Test
fun isEmpty_null_true(){
    Assert.assertEquals(StringUtils.isEmpty(null),true)
}

public static boolean isEmpty(@Nullable String value) {
    return (TextUtils.isEmpty(value) || value.trim().isEmpty());
}

除上述方法外,所有测试方法均有效并通过。我得到了这个 java.lang.NullPointerExceptionStringUtils.isEmpty()的实现上面也有提到。 StringUtils class 是用 Java 编写的,而测试用例文件是用 Kotlin 编写的。

也许可以代替: value.trim().isEmpty()
试试这个:value.trim().equals("")

问题出在这个 StringUtils.isEmpty() 方法本身,因为有时 那时你将 value 作为 null 传递,然后你调用 trim()导致 java.lang.NullPointerExceptionnull 值上的方法像这样修改方法以避免 java.lang.NullPointerException

public static boolean isEmpty(@Nullable String value) {
        return (TextUtils.isEmpty(value) || (value != null && value.trim().isEmpty()));
    }

如您所知,|| 运算符将在两侧调用代码(以获得一个真值)并且 null.trim().. 将导致异常。

由于 StringUtils.isEmpty 方法的预期行为是在传递 null 值时抛出异常,因此您应该编写单元测试以预期具有 null 值的异常如:

@Test(expected = NullPointerException::class)
fun isEmpty_null_exception(){
    StringUtils.isEmpty(null)
}

这里excepted用来断言这个测试方法抛出NullPointerException异常

注意: method is done with PowerMock框架,但这会违背测试代码实际行为的测试目的,所以使用上面推荐的方法来验证异常。您可能想创建一个模拟输入变量和模拟 trim 方法,但是您可以简单地使用非空输入字符串,不会有任何区别。

完整的解决方案,我有-
由于 app/build.gradle 中设置的默认值,我从 TextUtils.isEmpty() 中返回了 false,这出乎我的意料。

testOptions {
    unitTests.returnDefaultValues = true
}

参考-
我无法更改 build.gradle 文件中的值,因此我只需要单元测试方法的解决方案。有一种方法可以为 TextUtils.isEmpty() 方法提供实现并获取真正的返回值。

    @Before
    public void setup() {
        PowerMockito.mockStatic(TextUtils.class);
        PowerMockito.when(TextUtils.isEmpty(any(CharSequence.class))).thenAnswer(new Answer<Boolean>() {
            @Override
            public Boolean answer(InvocationOnMock invocation) throws Throwable {
                CharSequence a = (CharSequence) invocation.getArguments()[0];
                return !(a != null && a.length() > 0);
            }
        });
   }

参考-Need help to write a unit test using Mockito and JUnit4

我遇到了与 android.graphics.Color.parseColor() 相同的问题,因此上述解决方案适用于所有 类 位于 android 包中。