https://zenn.dev/nananaoto/articles/64debb8f918805

概要

ユニットテストでは、実行速度観点からも Infrastructure 層はモックすることが多いでしょう。 モックにもいくつか方法があり、テストライブラリでモックする方法やテスト用のクラスを使用して差し替えるなどがあります。

そこで、今回は下記 2 つの方法を比較してみます。

内容

前提

テスト対象コード

今回はユーザ情報を更新するユースケースを例に考えていきます。

具体的な実装は下記になります。

// ユーザのドメインモデル
export class User {
  constructor(public id: string, public name: string, public email: string) {}

  changeName(name: string): User {
    return new User(this.id, name, this.email);
  }

  changeEmail(email: string): User {
    return new User(this.id, this.name, email);
  }
}

// ユーザを永続化するための Repository のインターフェース
export interface UserRepository {
  findById(id: string): Promise<User | undefined>;
  update(user: User): Promise<void>;
}

// MySQL に永続化するための Repository の実装
export class UserMySQLRepository implements UserRepository {
  findById(_id: string): Promise<User | undefined> {
    // MySQLのデータベースからユーザを取得する
    throw new Error('Method not implemented.');
  }
  update(_user: User): Promise<void> {
    // MySQLのデータベースにユーザを更新する
    throw new Error('Method not implemented.');
  }
}

// ユーザ情報を更新するユースケース
export class UpdateUser {
  constructor(private userRepository: UserRepository) {}

  async execute(userId: string, updateParam: { name: string; email: string }): Promise<void> {
    const user = await this.userRepository.findById(userId);

    if (!user) {
      throw new Error('ユーザーが存在しません');
    }

    const updatedUser = user.changeName(updateParam.name).changeEmail(updateParam.email);

    await this.userRepository.update(updatedUser);
  }
}

テストコード