#はじめに
Dependency Injection(以下DI)はテストコードを書きやすくするために用いられることが多い手法です。
DIは二種類あるので、一つ一つ見ていきましょう。
#コンストラクタインジェクション
コンストラインジェクションはイニシャライズするときにインスタンスを注入します。
①プロトコルを用意する
②用意したプロトコルに準拠するクラスを用意する
③イニシャライズするときに準拠したクラスを注入する
// ①プロトコルを用意する
protocol UserRepositoryProtocol {
func login()
}
// ②用意したプロトコルに準拠するクラスを用意する
// 本番用クラス
class UserRepository: UserRepositoryProtocol {
func login() {
print("本番")
}
}
// ②用意したプロトコルに準拠するクラスを用意する
// 偽物クラス
class UserRepository偽物: UserRepositoryProtocol {
func login() {
print("偽物")
}
}
class UserUseCase {
private let repository: UserRepositoryProtocol
init(repository: UserRepositoryProtocol) {
self.repository = repository
}
func login() {
repository.login()
}
}
let repositroy = UserRepository()
// let repository偽物 = UserRepository偽物()
// ③イニシャライズするときに準拠したクラスを注入する
let userUseCase = UserUseCase(repository: repositroy)
userUseCase.login() // 本番
具体的なRepositoryクラス(UserRepositoryやUserRepository偽物)にUserUseCaseが依存するのではなく、インターフェース(プロトコル)に依存し、具体的なクラスをUserUseCaseをイニシャライズするときに注入します。これにより、本番用クラス(UserRepository)と偽物クラス(UserRepository偽物)をインスタンスする箇所で簡単に切り替えられるのでテストコードが書きやすくなります。
#セッターインジェクション
セッターインジェクションはイニシャライズした後にコンポーネントを注入します。
protocol ViewModelProtocol {
func printName()
}
class ViewModel: ViewModelProtocol {
func printName() {
print("REON")
}
}
class ViewController: UIViewController {
private var viewModel: ViewModelProtocol?
func inject(viewModel: ViewModelProtocol) {
self.viewModel = viewModel
}
func printName() {
viewModel?.printName()
}
}
let vc = UIStoryboard(name: "VC", bundle: nil)
.instantiateInitialViewController() as! ViewController
let viewModel = ViewModel()
vc.inject(viewModel: viewModel) // 注入
vc.printName() // REON
UIViewControllerをUIStoryboardから初期化する場合、コンストラクタインジェクションを使えないので、セッターインジェクションを用います。
しかし、セッターインジェクションは注入し忘れる可能性があるので、コンストラクタインジェクションを基本的に使えば良いでしょう。
#おわりに
DIはよく使うのでこれを機にマスターしておきましょう。