こんにちは。Dartの深淵を覗き込み、コードの「型」という規律を通じてソフトウェアの信頼性を担保しようとするあなたへ。
DartのSound Null Safety(健全なNull安全)は、単なるエラー回避の仕組みではありません。コンパイラが「ここにnullは絶対に存在しない」と数学的に保証するための、極めて強力な静的解析システムです。
今回は、テストコードにおいてこの「健全性」をどう維持し、モックやスタブを構築する際、なぜ多くのエンジニアが「Null許容型(Nullable)」の罠に陥るのか、その本質を紐解いていきましょう。
—
1. なぜテストで「Null安全」が崩壊するのか?
多くの初学者がテストで直面するのは、プロダクションコードでは厳格に守られている `Type` が、テスト(特にモック)の段階で「まあ、テストだし…」と安易に `null` を返してしまい、実行時エラーや意図しない挙動を引き起こすという問題です。
Dartのコンパイラは、`?` が付いていない型には「絶対にnullではない」という強い期待を寄せています。テストにおいてこれを破ることは、「テストがプロダクションの仕様を嘘で汚染する」ことと同義なのです。
よくあるアンチパターン
// ユーザー情報を取得するクラス(プロダクション)
class User {
final String name;
User(this.name);
}
// テスト用のスタブでやりがちなミス
// 戻り値が String? なのに、意図せず null を返してしまい
// 呼び出し側がクラッシュする原因になる
class MockUserRepository {
String? getName() => null; // 悪手:設計が null を許容していないのに null を返す
}
—
2. Null許容型を賢く扱う:モック設計の極意
テストコードを書く際、私たちは「型システムを欺く」のではなく、「型システムと対話する」必要があります。モックを設計する際の鉄則は、「プロダクションコードが期待する契約(Contract)を遵守すること」です。
アプローチA:ダミーデータの強制
もしメソッドが `String` を返すはずなら、`null` ではなく、空文字 `””` や、テスト専用の固定値 ` “Test User”` を返すようにしましょう。
アプローチB:遅延初期化と late の活用
テストのセットアップ時に値を注入したい場合、`late` を活用するのがDart流のスマートな解法です。
class UserTest {
// late を使うことで、「テスト実行時には必ず値が存在する」ことをコンパイラに伝えます
late String mockName;
void setUp() {
mockName = “Dart Champion”;
}
void testUser() {
print(mockName.length); // 安全! null チェックは不要です
}
}
—
3. `mockito` や `mocktail` を使う時の「Null安全」の境界線
`mockito` などのライブラリを使うと、`when(…).thenReturn(null)` を書きたくなる瞬間があるかもしれません。しかし、もし戻り値の型が `String`(非Null)であれば、コンパイラは即座に警告を出します。
この警告は「バグ」ではなく「警告灯」です。「あなたの設計しているスタブは、プロダクションコードの生存条件を満たしていませんよ」というDart VMからのメッセージなのです。
正しいスタブの書き方
// mocktail を使用した例
when(() => mockUserRepository.getName()).thenReturn(“Default Name”);
// 戻り値の型と一致する値を返すのが、健全な Null 安全の作法です。
もし「どうしても失敗するケース」をテストしたいなら、戻り値を `null` にするのではなく、例外を投げる(Exceptionをスローする)設計に切り替えてください。
// 「値がない」ことを表現したい場合の正しい設計
when(() => mockUserRepository.getName()).thenThrow(UserNotFoundException());
—
4. 陥りやすい罠: `!` 演算子の乱用
テストコードでコンパイルエラーを消すために、安易に `variable!` と書くコードを見かけます。これは「Null安全というシートベルトを自ら外している」のと同じです。
テストコードであっても、以下のルールを守りましょう。
1. `!` は最後の手段: 型推論で解決できない時以外は使わない。
2. 型ガードを活用: `if (value != null)` を使って、Dartに型の絞り込み(Type Promotion)をさせる。
3. テストの期待値: 「nullが返るはずがない」と断言できるなら、それはコードの設計ミスである可能性が高いです。
—
最後に:Dartを掌握するということ
DartのNull安全は、開発者を縛るための鎖ではなく、「コンパイル時にバグを撲滅するための防壁」です。
テストコードで `null` を安易に許容してしまうと、その緩さがプロダクションコードの設計を徐々に腐らせていきます。テストを書く時は、そのコードが「本番環境でどう動くべきか」という設計書であることを忘れないでください。
ここをクリアすれば、あなたの書くDartコードの堅牢性は、他の言語の追随を許さないレベルに引き上げられます。Dartの型システムを味方につけて、最高のソフトウェアを一緒に作り上げていきましょう。
何か分からないことがあれば、いつでも聞いてくださいね。あなたのコードがより健全で、より洗練されたものになることを心から応援しています!