如何使用浓缩咖啡在仪器测试中注入模拟活动演示者



我已经尝试了一个星期了。我已经抓取了所有可用的文章,但它们的实现或示例不足或停留在浓缩咖啡测试的步骤上。

我的Android应用程序遵循MVP架构(并且是Java(

场景:[仅举一个例子] 我有一个使用 Dagger2 获得HomePresenterHomeActivity。(在HomeModule中提供方法,通过HomeComponent中的void inject(HomeActivity activity)公开。

在我的浓缩咖啡测试中HomeActivity我想注入一个模拟礼物。 我没有通过AppComponentAppModule中公开此依赖项。网络上的大多数示例都这样做(所以他们只是创建一个新的测试应用程序,然后做需要的(

我不想使用 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 个额外操作(您可能还想查看示例(。

  1. HomeActivity组件的实例化委托给一些抽象。
  2. 替换插桩测试中抽象的实现以提供模拟。

我将在下面的示例中使用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)

对于插桩测试,请创建扩展HomeComponentTestHomeComponent

@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测试

最新更新