의존성 주입.. Dependency injection ... 줄여서... DI....
이걸 왜하느냐!
라고 물으시면..
아주 간단하게,
테스팅을 위해서!
라고 답할 수 있지 않을까요..?
지금과 같은 MVVM패턴에서
뷰모델을 테스팅한다고 칩시다.
그럼 뷰모델을 테스팅하려면 뷰모델이 의존하고 있는 모델은.. 어떻게 만들어서 뷰모델에게 줘야 뷰모델을 테스팅 할 수 있을까요?
간단한 방법으로는 모델을 내부에서 생성하지 않고 생성자의 인자로 주는 것입니다.
ViewModel{
val model = Model()
}
과 같이 하지 않고
ViewModel(val model){
}
이렇게
그러면 뷰모델을 테스팅모듈에서 생성할 때 테스팅용 모델을 뷰모델의 생성자로 '주입' 해줌으로서 뷰모델을 테스팅하기 쉽게 할 수 있는 것이죠.
근데 이걸 일일이 한다?
꽤.. 불편하고 버그도 많게 될거 같군요..
그래서 이러한 의존성 주입 작업을 편하게 해주는 몇가지 라이브러리가 있습니다.
그중 가장 대표적인것이 Dagger2 !
근데... 대거는.. 너무 어렵습니다!
솔직히 저같은 초보는..
의존성이 적은 MVVM패턴 같은 데서는
대거 배워서 적용한다음 대거를 위해 프로젝트 구조를 싹 다 바꾸는 것보다..
그냥 라이브러리 없이 의존성 주입하는게 더 편합니다...ㅜㅜㅜ
근데, Koin은 너무 편합니다!
학습할 것도 많이 없고, 바꿀것도 많이 없고, 코틀린에 특화되어있고, 뷰모델에 또한 특화되어있기도 하지요.
관련되서는 이 링크를 한번 보시면 좋을듯 합니다.
그래서, 저는 코인을 쓰고, 이번 글에서는 코인에 관해 간단하게 설명해보겠습니다.
일단 코인 공식 홈페이지입니다.
이건 깃헙 리포지토리 입니다.
https://github.com/InsertKoinIO/koin
사용방법을 말씀드리며 설명을 해보겠습니다.
일단 디펜던시에 추가해줍시다
// koin
implementation "org.koin:koin-androidx-scope:1.0.2"
implementation "org.koin:koin-androidx-viewmodel:1.0.2"
AndroidX용 입니다. AndroidX를 안쓰시면 깃헙 레포지토리 리드미등을 참고해서 다른걸로 바꿔주세요
먼저 의존성 주입에 사용할 모듈을 짜봅시다.
이 모듈이 뭐냐면, 간단하게 말해서 의존성 주입을 하는 실제 코드, 혹은 의존성 주입을 위한 설계도, 정도로 이해해주시면 됩니다.
var modelPart = module {
factory<DataModel> {
DataModelImpl()
}
}
var viewModelPart = module {
viewModel {
MainViewModel(get())
}
}
var myDiModule = listOf(modelPart, viewModelPart)
끝입니다.
간단하죠!
대거로 짰으면 벌써 클래스 6개는 나왔습니다...
일단 factory{}와 viewModel{}이 보이네요
팩토리는 말그대로 공장입니다. DataModelImpl()이라는 클래스를 뚝딱뚝딱 만들어 주죠
그러면 이제 다른 클래스에서 해당 부분이 필요하다면 단순히 get()을 해주면 팩토리로 만든 클래스가 쏘옥~하고 들어갑니다.
팩토리외에도 single{}이 있는데, 이건 싱글톤패턴처럼 어플리케이션에서 단 하나만 만듭니다. 저는 보통 Retrofit을 통해 만든 서비스 클래스를 single로 만듭니다.
이렇게 얻은 객채들은 방금 말한것처럼 get()으로 넣는것 이외에도 by inject()를 통해서도 얻을 수 있습니다.
그리고 viewModel{}은 말 그대로 뷰모델을 만듭니다.
액티비티에서 by viewModel()을 통해서 얻어올 수 있죠.
두번째로 Application 클래스를 상속 한뒤 onCreate에 딱 한줄만 넣습니다.
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin(applicationContext, myDiModule)
}
}
startKoin(context, module)
이러면 이제 의존성이 주입됩니다.
(Application 클래스를 상속한 뒤 메니페스트에서
<application
android:name=".MyApplication"
와 같이 설정해 주는걸 잊지 마세요!)
주입할 때는 이런식으로 코드 내에서나,
val service : BusinessService by inject()
이렇게 생성자나,
class Controller(val service : BusinessService){
fun hello() {
// service is ready to use
service.sayHello()
}
}
이렇게 뷰모델을 주입할 수 있습니다.
val vm : MyViewModel by viewModel()
추가로 테스팅을 할 때에는
// Just tag your class with KoinTest to unlick your testing power
class SimpleTest : KoinTest {
// lazy inject BusinessService into property
val service : BusinessService by inject()
@Test
fun myTest() {
// You can start your Koin configuration
startKoin(myModules)
// or directly get any instance
val service : BusinessService = get()
// Don't forget to close it at the end
stopKoin()
}
}
이렇게 해주면 됩니다.
실제로 이전 게시물의 메인 액티비티에서는
override val viewModel: MainViewModel by viewModel()
'코딩 > 안드로이드' 카테고리의 다른 글
Android Kotlin MVVM패턴으로 간단한 검색 앱 만들기 - 4. Livedata를 통한 데이터 바인딩 (10) | 2019.01.03 |
---|---|
Android Kotlin MVVM패턴으로 간단한 검색 앱 만들기 - 3. RxJava + Retrofit를 통한 네트워킹 및 옵저빙 (8) | 2019.01.02 |
Android Kotlin MVVM패턴으로 간단한 검색 앱 만들기 - 1. BaseView, BaseViewModel을 작성하여 MVVM의 토대 만들기 (7) | 2018.12.29 |
androidx view.doOnLayout (0) | 2018.12.27 |
Android studio code coverage시 Robolectric 사용할 때 ComplexColor 부분 에러 해결 (0) | 2018.09.17 |