Tooling 中級

JUnit 6はJSpecifyの@NullMarkedを採用し、アサーションAPI全体でnullコントラクトを明示化する。

✕ JUnit 5
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class UserServiceTest {

    // JUnit 5: no null contracts on the API
    // Can assertEquals() accept null? Check source...
    // Does fail(String) allow null message? Unknown.

    @Test
    void findUser_found() {
        // Is result nullable? API doesn't say
        User result = service.findById("u1");
        assertNotNull(result);
        assertEquals("Alice", result.name());
    }

    @Test
    void findUser_notFound() {
        // Hope this returns null, not throws...
        assertNull(service.findById("missing"));
    }
}
✓ JUnit 6
import org.junit.jupiter.api.Test;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import static org.junit.jupiter.api.Assertions.*;

@NullMarked  // all refs non-null unless @Nullable
class UserServiceTest {

    // JUnit 6 API is @NullMarked:
    // assertNull(@Nullable Object actual)
    // assertEquals(@Nullable Object, @Nullable Object)
    // fail(@Nullable String message)

    @Test
    void findUser_found() {
        // IDE warns: findById returns @Nullable User
        @Nullable User result = service.findById("u1");
        assertNotNull(result); // narrows type to non-null
        assertEquals("Alice", result.name()); // safe
    }

    @Test
    void findUser_notFound() {
        @Nullable User result = service.findById("missing");
        assertNull(result); // IDE confirms null expectation
    }
}
このコードに問題がありますか? お知らせください。
📜

明示的なコントラクト

JUnit 6モジュールへの@NullMarkedがnullのセマンティクスをAPIに直接ドキュメント化します——ソースを読む必要はありません。

🛡️

コンパイル時の安全性

非nullが期待される場所にnullが渡される場合、IDEや解析ツールが警告を出し、テスト実行前にバグを検出できます。

🌐

エコシステム標準

JSpecifyはSpring・Guava・その他のプロジェクトでも採用されており、スタック全体で一貫したnullセマンティクスを提供します。

旧来のアプローチ
アノテーションなしAPI
モダンなアプローチ
@NullMarked API
JDKバージョン
17
難易度
中級
JUnit 6とJSpecifyによるnull安全性
利用可能

JUnit 6.0(2025年10月、Java 17以上が必要)以降、利用可能

JUnit 5には標準化されたnullabilityアノテーションがなく、アサーションのパラメーターや戻り値がnullになりえるかを開発者が推測するしかありませんでした。JUnit 6はモジュール全体にJSpecifyを採用しています。@NullMarkedアノテーションにより、未アノテートの型はデフォルトで非nullになり、@Nullableが例外を明示します。AssertionsクラスはassertNull(@Nullable Object actual)やfail(@Nullable String message)などのパラメーターを明示的にアノテートしており、NullAwayやError ProneなどのIDEや静的解析ツールがnullの誤用をコンパイル時に検出できます。

共有 𝕏 🦋 in