我已经尝试了一个星期了。我已经抓取了所有可用的文章,但它们的实现或示例不足或停留在浓缩咖啡测试的步骤上。
我的Android应用程序遵循MVP架构(并且是Java(
场景:[仅举一个例子] 我有一个使用 Dagger2 获得HomePresenter
HomeActivity
。(在HomeModule
中提供方法,通过HomeComponent
中的void inject(HomeActivity activity)
公开。
在我的浓缩咖啡测试中HomeActivity
我想注入一个模拟礼物。 我没有通过AppComponent
在AppModule
中公开此依赖项。网络上的大多数示例都这样做(所以他们只是创建一个新的测试应用程序,然后做需要的(
我不想使用 productFlavors 的方式来注入或提供模拟类,因为它不能让我控制Mockito.when
方法。
所以基本上。我想注入一个模拟演示者,我可以在其中做任何Mockito.when()
的事情,以便在浓缩咖啡中进行单元测试。
我的代码如下。
首页组件
@HomeScope
@Component(modules = HomeModule.class,dependencies = AppComponent.class)
public interface HomeComponent {
void inject(HomeActivity activity);
}
首页模块
@Module
public class HomeModule {
private final IHomeContract.View view;
public HomeModule(IHomeContract.View view) {
this.view = view;
}
@Provides
@HomeScope
public IHomeContract.Presenter presenter(FlowsRepository flowsRepository, UserRepository userRepository, LoanRepository loanRepository) {
return new HomePresenter(view, flowsRepository, userRepository, loanRepository);
}
}
应用组件
@Component(modules = {AppModule.class,RepositoryModule.class})
@AppScope
public interface AppComponent {
void inject(App app);
FlowsRepository flowRepository();
LoanRepository loanRepository();
UserRepository userRepository();
}
应用模块
@Module
public class AppModule {
private Context appContext;
public AppModule(@NonNull Context context) {
this.appContext = context;
}
@Provides
@AppScope
public Context context() {
return appContext;
}
}
应用程序
component = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
component.inject(this);
主页活动
HomeComponent component = DaggerHomeComponent.builder()
.appComponent(((App) getApplication()).getComponent())
.homeModule(new HomeModule(this))
.build();
再来一次。在我的测试(浓缩咖啡(中,我想注入一个模拟的HomePresenter,由Mockito设置。所以我可以对我的观点进行单元测试。
解决问题的关键点是拥有这样一个dagger模块,在HomeActivity
的仪器化测试中提供一个模拟演示者,而不是"真实"的演示者。
为此,需要执行以下 2 个额外操作(您可能还想查看示例(。
- 将HomeActivity组件的实例化委托给一些抽象。
- 替换插桩测试中抽象的实现以提供模拟。
我将在下面的示例中使用Kotlin。
定义委托接口:
interface HomeComponentBuilder {
fun build(view: IHomeContract.View): HomeComponent
}
将HomeComponent
初始化从HomeActivity
移动到委托实现:
class HomeComponentBuilderImpl constructor(private val app: App) : HomeComponentBuilder {
override fun build(view: IHomeContract.View): HomeComponent =
DaggerHomeComponent.builder()
.homeModule(HomeModule(view))
.build()
}
使委托位于应用程序"范围"中,以便可以交换其实现以进行插桩测试:
interface App {
val homeComponentBuilder: HomeComponentBuilder
...
}
App
实现现在应包含
class AppImpl : Application(), App {
override val homeComponentBuilder: HomeComponentBuilder by lazy {
HomeComponentBuilderImpl(this@AppImpl)
}
...
}
HomeActivity
中的组件初始化如下所示:
(application as App)
.homeComponentBuilder
.build(this)
.inject(this)
对于插桩测试,请创建扩展HomeComponent
的TestHomeComponent
:
@HomeScope
@Component(modules = [TestHomeModule::class])
interface TestHomeComponent : HomeComponent
其中TestHomeModule
提供模拟演示者
@Module
class TestHomeModule {
@Provides
fun providePresenter(): IHomeContract.Presenter = mock()
}
剩下要做的就是使测试委托实现
class TestHomeComponentBuilderImpl : HomeComponentBuilder {
override fun build(view: IHomeContract.View): HomeComponent =
DaggerTestHomeComponent.builder()
.testTestHomeModule(TestHomeModule())
.build()
}
并在TestAppImpl
中初始化它
class TestAppImpl : Application(), App {
override val homeComponentBuilder: HomeComponentBuilder by lazy {
TestHomeComponentBuilderImpl()
}
...
}
其余的都是标准的。创建使用TestAppImpl
的自定义AndroidJUnitRunner
:
class TestAppRunner : AndroidJUnitRunner() {
override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application = Instrumentation.newApplication(TestAppImpl::class.java, context)
}
并将其添加到app
模块build.gradle
defaultConfig {
testInstrumentationRunner "your.package.TestAppRunner"
...
}
使用示例:
@RunWith(AndroidJUnit4::class)
class HomeActivityTest {
private lateinit var mockPresenter: IHomeContract.Presenter
@get:Rule
val activityRule = ActivityTestRule(HomeActivity::class.java)
@Before
fun setUp() {
mockPresenter = activityRule.activity.presenter
}
@Test
fun activity_onCreate_presenter_should_onViewCreated() {
verify(mockPresenter).someMethod()
}
}
所以。您的问题是您需要创建一个模块,该模块提供模拟演示器进行测试,而不是"真实"演示者。
这里有一篇很好的文章:用dagger测试