随着 JUnit 6.0.0 的发布,维护者在所有 JUnit 模块中采用了 JSpecify 空值性注解。这意味着 JUnit 中的方法参数、返回类型和其他 API 元素现在都已标注,以明确声明它们是否接受或返回 null。
因此,测试(或扩展)更安全,并且您可以在编译时或 IDE 时获得提示,而无需仅依赖运行时行为。
如果我们将一个参数标注为
@NonNull,并且在运行时意外传递null,程序仍然会运行,并且可能只有在我们尝试使用该 null 值时才会抛出 NullPointerException。该注解本身并不会将任何空值检查插入到方法中。
1. 与空值相关的注解 (通过 JUnit 6 中的 JSpecify)
我们可以使用以下注解来指定测试的null相关行为
| 注解 | 描述 / 用途 |
|---|---|
@Nullable | – 这会将用法类型(参数类型、返回类型、字段类型等)标记为nullable。 – 此值可能为 null。 – 这会告知 IDE/工具/静态分析,并帮助用户了解空值安全契约。 |
@NonNull | – 这会将用法类型标记为非 null。 – 此值一定不能为 null。 – 这可确保调用者/实现将它视为非 null,从而提供更强的保证。 |
@NullMarked | – 这是一个包/类/模块级别的注解。 – 这表示在注释范围内,未注释的类型默认应被视为非空(除非显式标记为 @Nullable)。– 这有助于减少冗余,即不必标记每种类型为非空,而只需标记可为空的类型。 |
使用
@NullMarked可以减少注释的繁琐。与其显式标记每种非空类型,不如可以注释整个类/包/模块,然后仅标记那些可为空的类型。
2. JUnit 6 @Nullable 示例
在 JUnit 6 中,@Nullable 来自 JUnit 6 采用的 JSpecify 注解,用于指示参数或返回值是否可以为 null。 这不会改变测试执行,但它有助于 IDE 检查、静态分析和 Kotlin 互操作。
这是一个简单的示例,展示了测试中的 @Nullable
import org.junit.jupiter.api.Test;
import org.jspecify.annotations.Nullable;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
class NullableExampleTest {
// A simple method that may return null
@Nullable
String getNullableString(boolean returnNull) {
if (returnNull) {
return null;
} else {
return "Hello, JUnit 6!";
}
}
@Test
void testNullableReturn() {
// Test case 1: method returns a string
String result1 = getNullableString(false);
assertEquals("Hello, JUnit 6!", result1);
// Test case 2: method returns null
String result2 = getNullableString(true);
assertNull(result2); // @Nullable tells the IDE/static analysis that this can be null
}
@Test
void testNullableParameter() {
// @Nullable can also be used on parameters
printMessage(null);
printMessage("JUnit 6 is great!");
}
void printMessage(@Nullable String message) {
if (message == null) {
System.out.println("No message provided");
} else {
System.out.println(message);
}
}
}
程序输出
No message provided
JUnit 6 is great!
3. JUnit 6 @NonNull 示例
在 JUnit 6 中,@NonNull 表示一个方法不应返回 null,或者一个参数不应为 null。 IDE、静态分析工具和 Kotlin 互操作使用此元数据来捕获潜在的空安全违规,在编译时。
这是一个简单的 JUnit 6 示例
import org.junit.jupiter.api.Test;
import org.jspecify.annotations.NonNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
class NonNullExampleTest {
// Method guarantees a non-null return value
@NonNull
String getNonNullMessage(boolean condition) {
if (condition) {
return "JUnit 6 rocks!";
} else {
return "Null is not allowed!"; // must return non-null
}
}
@Test
void testNonNullReturn() {
String result = getNonNullMessage(true);
assertEquals("JUnit 6 rocks!", result);
String result2 = getNonNullMessage(false);
assertEquals("Null is not allowed!", result2);
}
@Test
void testNonNullParameter() {
printMessage("Hello, JUnit 6!");
// printMessage(null); // IDE/static analyzer will warn: null not allowed
}
// Parameter marked @NonNull → must not be null
void printMessage(@NonNull String message) {
// No need to check for null; tools assume non-null
System.out.println(message.toUpperCase());
}
}
程序输出
HELLO, JUNIT 6!
4. JUnit 6 @NullMarked 示例
在 JUnit 6 中,@NullMarked 是一个包级、类级或模块级注解,表示该范围内的所有未注解的类型默认情况下都为非空。 您只需要使用 @Nullable 注解可以为null 的值。
这是一个使用 @NullMarked 的 JUnit 6 示例
import org.jspecify.annotations.Nullable;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.NullMarked;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
@NullMarked // All unannotated types in this class are treated as @NonNull
class NullMarkedExampleTest {
// Return type is non-null by default because of @NullMarked
String getMessage(boolean condition) {
return condition ? "JUnit 6 is awesome!" : "Null is not allowed!";
}
// Parameter is non-null by default
void printMessage(String message) {
System.out.println(message.toUpperCase());
}
// Only mark explicitly nullable parameters/returns
@Nullable
String getNullableMessage(boolean condition) {
return condition ? "Some message" : null; // nullable allowed
}
@Test
void testNonNullBehavior() {
String msg = getMessage(true);
assertEquals("JUnit 6 is awesome!", msg);
// IDE or static analysis will warn if you try to pass null here:
// printMessage(null); // ❌ warning
printMessage(msg); // ✅ OK
}
@Test
void testNullableBehavior() {
String maybeNull = getNullableMessage(false);
assertNull(maybeNull); // ✅ allowed because @Nullable
}
}
程序输出
JUNIT 6 IS AWESOME!
5. 结论
JUnit 6 采用的 JSpecify 空值注解 @Nullable、@NonNull 和 @NullMarked 代表了类型安全和开发人员指导方面的一大改进。 虽然这些注解不会强制执行运行时空值检查,但它们显著提高了代码安全性、可维护性和可读性,帮助开发人员编写更可靠和更具表现力的测试。
祝您学习愉快!!
评论