単体テストを効果的に実施するためには、テスト対象のコードを他の依存関係から分離することが重要。依存関係に直接アクセスすると、テストが複雑になり、外部リソース(データベースや外部APIなど)に依存するためにテストが不安定になることがある。以下のポイントに注意してコードを分離する。
外部リソースに依存するクラスやメソッドは、依存関係を直接持つのではなく、インターフェースを通じて注入するのが良い。この方法を**依存関係の注入(Dependency Injection: DI)**という。DIを使うことで、テスト時に実際のリソースをモックに置き換え、テスト環境を簡単に整えることができる。
例:
csharppublic class AuthService
{
private readonly IUserRepository _userRepository;
public AuthService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public bool Login(string username, string password)
{
var user = _userRepository.GetUserByUsername(username);
return user != null && user.Password == password;
}
}
このように、AuthService
はIUserRepository
に依存しており、テスト時にIUserRepository
の実装をモックに置き換えることができる。
テストがしやすいコードを書くためには、クラス同士の結合をできるだけ緩くする(疎結合にする)必要がある。これは、クラスが独立してテスト可能な状態にするための基本的な設計原則だ。クラスが一つの機能に集中し、他のクラスに過度に依存しないようにすることで、テストの複雑さを減らし、管理しやすくする。
SOLID原則を意識して設計すると、疎結合なクラスを作成できる。特に「単一責任原則」(Single Responsibility Principle: SRP)を守ることで、クラスやメソッドのテスト範囲を明確にし、テストのしやすさが向上する。
データベースやファイルシステム、外部APIなどの外部リソースに依存すると、テストの実行速度が遅くなったり、外部リソースの状態によってテスト結果が不安定になったりする。これを避けるために、依存関係の抽象化を行い、モックやスタブを利用するのが一般的。
悪い例:
csharppublic class UserService
{
public bool SaveUser(User user)
{
// 実際のデータベースに接続して保存する
using (var db = new DatabaseConnection())
{
return db.Save(user);
}
}
}
良い例:
csharppublic class UserService
{
private readonly IUserRepository _userRepository;
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public bool SaveUser(User user)
{
return _userRepository.Save(user);
}
}
依存するリポジトリをインターフェースとして外部から注入することで、テスト時にはモックを使って依存を取り除くことができる。
このように、依存関係の注入や疎結合化を通じてテスト対象コードを分離することで、単体テストが効率的かつ信頼性の高いものになる。テスト環境の整備を簡単にすることができ、外部リソースの影響を排除できる点が大きなメリット。