好的,所以我决定仔细研究一下在我的项目中实现junit测试。 然后,我偶然发现了一篇文章,其中写到了使用诸如 Dagger2 和 Koin 这样的依赖注入框架来简化测试的重要性。
我尝试阅读-什么是 DI 。我将其理解为解决A类依赖对象(例如B类和C类)的一种方式。
我现在通常要做的是:
在活动中,我创建ViewModel
。 ViewModel
需要访问数据,因此对于数据,我拥有SomeRepository
类。然后,我通常通过SomeRepository
构造函数或使用属性注入传递ViewModel
。据我了解,如果我没记错的话,那也是某种依赖注入(如果我记错了,请纠正我)。
那么,如果我现在开始使用Dagger 2,我将获得什么好处?也许简单的代码比较会使它更清晰?预先感谢。
活动:
val someRepository = SomeRepository()
viewModel.init(someRepository)
在ViewModel中:
class SomeViewModel : ViewModel {
private lateinit var repository: SomeRepository
fun init(val someRepo: SomeRepository) {
this.repository = someRepo
}
}
答案 0 :(得分:5)
Dagger通过其自己的依赖关系图促进依赖关系的解耦。我们需要告诉匕首类如何生成例如它需要一个构造函数参数。定义后,它将遍历所有依赖项并从低级别开始创建它们。如果我们不能在构造函数中注入任何依赖关系,例如改造后,我们可以手动告诉dagger如何使用@Provides
注释创建if的实例。
让我们看一个例子:
第1个依存关系-个性化方式
@Module
class NetworkModule {
@Provides
fun provideRetrofit() : Retrofit
}
依赖项2 -取决于依赖项1
class ApiService constructor (@Inject retrofit: Retrofit){
}
依赖性#3 -取决于依赖性#2
class SomeRepository constructor (@Inject apiService: ApiService){
}
依赖性#4 -取决于依赖性#3
class SomeViewModel constructor (@Inject someRepository: SomeRepository) : ViewModel {
}
Dagger将在运行时生成所有依赖项。当您运行应用程序时,每个依赖项已准备就绪,可以直接注入构造函数中。您还可以通过字段注入
注入任何依赖项class MainAcitivty : AppCompatActivity(){
@Inject someRepository: SomeRepository
}
符合您当前的做法:
val someRepository = SomeRepository()
viewModel.init(someRepository)
SomeRepository()
的新实例SomeRepository()
具有任何依赖关系,这些依赖关系还将创建多次SomeRepository()
的依赖项,将很难测试。在单元测试中,我们有兴趣测试单元而不是其依赖项。 答案 1 :(得分:1)
Pro1:用外行的话来说,DI对于编写解耦的代码很重要,这使编写单元测试变得容易。
Pro2:它还从父类中抽象出对象的依赖关系。例如,在您的用例中,Activity
不是直接使用SomeRepository
,而是仍然需要了解它。但是,相反,如果您像这样使用构造函数注入:
class SomeViewModel constructor (@Inject someRepository: SomeRepository) : ViewModel {
}
您的活动类只需要处理SomeViewModel
对象,而SomeViewModel
使用的任何依赖项都不在乎。
Pro3:DI使创建和访问单例对象变得非常容易。
只需定义一个如下所示的类,即可在应用程序中的任何位置获取MySingleton
类的单个实例。
@Singleton
class MySingleton @Inject constructor() {}
OR
@Provides @Singleton mySingleton() {}