「テストのしやすさ」を考えたクラス設計とは?Javaを例に新人エンジニア向けにやさしく解説!

こんにちは。ゆうせいです。

今回はソフトウェア開発の現場で非常に重要な考え方、「テストしやすいクラス設計」について、新人エンジニアの方向けに解説します。

コードを書く力だけでは、良い設計にはなりません。
「そのコードをテストしやすいかどうか」は、プロの設計力が試されるポイントです!


なぜ「テストのしやすさ」が大事?

  • バグの早期発見ができる
  • 変更に強いコードが書ける
  • 信頼できるコードを保ちやすくなる

つまり、テストしやすい設計は、安全で育てやすいコードベースにつながります。


テストしやすいクラス設計の4原則(Javaを前提に)

1. 依存関係を注入する(Dependency Injection)

クラスの中で直接他のクラスをnewで生成すると、テストしにくくなります。

// ❌ 悪い例:自分で依存を作ってしまっている
class OrderService {
    private PaymentProcessor processor = new PaymentProcessor();

    void processOrder() {
        processor.process();
    }
}

こうすると、テストで PaymentProcessor をモックに差し替えるのが難しい…


✅ 良い例:依存性注入を使う

class OrderService {
    private PaymentProcessor processor;

    // コンストラクタで注入
    OrderService(PaymentProcessor processor) {
        this.processor = processor;
    }

    void processOrder() {
        processor.process();
    }
}

こうすることで、テスト時にモックやスタブを渡せます。

PaymentProcessor mock = new MockPaymentProcessor();
OrderService service = new OrderService(mock);


2. 状態ではなく振る舞いに注目する

「状態ではなく振る舞いに注目する」とは、オブジェクトの内部データ(状態)ではなく、そのオブジェクトが「どう動くか(振る舞い)」に注目して設計・テストを行う考え方です。たとえば、「この変数がこうなっているか」ではなく、「このメソッドを呼んだ結果、どういう反応や副作用があったか」を重視します。

この考え方はブラックボックステストにも通じます。内部の仕組みは気にせず、入力と出力の関係、もしくは期待される動作にフォーカスすることで、実装変更に強いテストになります。

また、モックを使って「このメソッドが呼ばれたか?」という振る舞いの確認もこの一種です。状態だけを見るよりも、より意図に近いテストが可能です。

結果として、実装に依存しない柔軟な設計とテストができるようになるというメリットがあります。特にチーム開発やリファクタリングの多いプロジェクトでは、この考え方がとても重要になります。

テストでは「値を見て確認する」だけでなく、「どう振る舞ったか」も大事です。

→ だからこそ、「副作用を持つ処理」は分離しておくのがコツ!


3. 単一責任の原則(SRP)を守る

クラスがいろんな責任を持っていると、テスト対象が増えてしまい、
「ここを直すと他も壊れる」ような不安定なコードになります。

✅ クラスは1つの目的に絞る!

// ❌ NG:処理とデータアクセスが混ざってる
class UserService {
    void registerUser(User user) {
        saveToDatabase(user);     // DB操作
        sendWelcomeEmail(user);   // メール送信
    }
}

👇 分割するとテストしやすく!

class UserService {
    private UserRepository repository;
    private EmailService emailService;

    UserService(UserRepository repo, EmailService email) {
        this.repository = repo;
        this.emailService = email;
    }

    void registerUser(User user) {
        repository.save(user);        // テスト可能!
        emailService.send(user);      // モックで差し替え可能!
    }
}


4. インターフェースで抽象化する

モックやスタブを差し込めるようにするためには、
インターフェース(interface)を活用することがポイント!

interface EmailService {
    void send(User user);
}

class RealEmailService implements EmailService {
    public void send(User user) {
        // 実際のメール送信処理
    }
}

class MockEmailService implements EmailService {
    public void send(User user) {
        System.out.println("モックメール送信:成功");
    }
}

→ テスト時には MockEmailService を渡せば、外部の仕組みに依存せずに動作確認できます!


テストしにくいクラスの特徴まとめ

特徴問題点
自分で依存オブジェクトを作るモックやスタブを使えない
複数の責任を持っているテスト範囲が広すぎて壊れやすい
外部システムと密結合テスト中に本番のAPIを叩いてしまう
インターフェースを使っていない柔軟な差し替えができない

まとめ:設計はテストしやすさから考えよう!

  • テストしやすい設計 = 保守しやすい設計
  • クラスの中でnewしない、責任を分ける、外部との接点を抽象化する
  • モックやスタブを差し替えられるようにすることがテストの鍵!

次のステップ

  • 実際にDIを使ったクラスを自作してテストコードを書いてみよう
  • Mockitoなどのモックライブラリにも触れてみよう
  • 「SOLID原則」や「クリーンアーキテクチャ」に進んで設計力を磨こう!

「テストしやすさ」を意識するだけで、コードの質は見違えるほど上がりますよ!

セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。