gpt4 book ai didi

android - 为仪器测试注入(inject) espresso 规则的依赖项

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:10:17 26 4
gpt4 key购买 nike

android studio 3.4.1
dagger-android 2.21

我正在使用 dagger-android 将我的 OKHttpClient 注入(inject)到 espresso 规则中。但是还没有找到一种方法来做到这一点,我尝试了很多不同的事情。

这是我正在使用的规则,我正在尝试将 okHttpClient 注入(inject)其中

class OkHttpIdingResourceRule(application: Application) : TestRule {

/* My attempt below - but not working */
private val testApplication =
InstrumentationRegistry.getInstrumentation().targetContext.applicationContext
as AndroidTestGoWeatherApplication

// private val testApplication = application.applicationContext as AndroidTestGoWeatherApplication
private val component = testApplication.component as AndroidTestGoWeatherPresentationComponent
private val okHttpClient: OkHttpClient = component.okHttpClient()

private val idlingResource: IdlingResource = OkHttp3IdlingResource.create("okhttp", okHttpClient)

override fun apply(base: Statement?, description: Description?): Statement {
return object: Statement() {
override fun evaluate() {
IdlingRegistry.getInstance().register(idlingResource)
base?.evaluate()
IdlingRegistry.getInstance().unregister(idlingResource)
}
}
}
}

这是我的 AndroidTestGoWeatherApplication

class AndroidTestGoWeatherApplication : GoWeatherApplication(), HasActivityInjector {
@Inject
lateinit var activityInjector: DispatchingAndroidInjector<Activity>

override fun activityInjector(): AndroidInjector<Activity> = activityInjector
}

我的申请

open class GoWeatherApplication : Application(), HasActivityInjector, HasSupportFragmentInjector, HasServiceInjector {

@Inject
lateinit var dispatchingAndroidActivityInjector: DispatchingAndroidInjector<Activity>

@Inject
lateinit var dispatchingAndroidFragmentInjector: DispatchingAndroidInjector<Fragment>

@Inject
lateinit var dispatchingAndroidServiceInjector: DispatchingAndroidInjector<Service>

lateinit var component: GoWeatherComponent

override fun onCreate() {
super.onCreate()

component = DaggerGoWeatherComponent
.builder()
.application(this)
.build()

component.inject(this)
}

override fun activityInjector(): AndroidInjector<Activity> {
return dispatchingAndroidActivityInjector
}

override fun supportFragmentInjector(): AndroidInjector<Fragment> {
return dispatchingAndroidFragmentInjector
}

override fun serviceInjector(): AndroidInjector<Service> {
return dispatchingAndroidServiceInjector
}
}

我的主要应用组件

GoWeatherComponent
@Singleton
@Component(modules = [
AndroidSupportInjectionModule::class,
ActivityBuilder::class,
NetworkModule::class,
GoWeatherApplicationModule::class])
interface GoWeatherComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: GoWeatherApplication): Builder

fun build(): GoWeatherComponent
}

fun inject(application: GoWeatherApplication)
}

我的测试应用程序组件

@Singleton
@Component(modules = [
AndroidSupportInjectionModule::class,
TestNetworkModule::class,
TestGoWeatherApplicationModule::class,
TestForecastModule::class])
interface AndroidTestGoWeatherPresentationComponent : AndroidInjector<AndroidTestGoWeatherApplication> {

@Component.Builder
abstract class Builder : AndroidInjector.Builder<AndroidTestGoWeatherApplication>() {
abstract fun applicationModule(TestApplicationModule: TestGoWeatherApplicationModule): Builder

abstract fun testNetworkModule(testNetworkModule: TestNetworkModule): Builder
}

fun okHttpClient(): OkHttpClient
}

这是我创建 OkHttpClient 的 TestNetworkModule

@Module
class TestNetworkModule {

@Singleton
@Provides
fun httpLoggingInterceptor(): HttpLoggingInterceptor {
val loggingInterceptor = HttpLoggingInterceptor()

loggingInterceptor.level = if(BuildConfig.DEBUG) {
HttpLoggingInterceptor.Level.BODY
}
else {
HttpLoggingInterceptor.Level.NONE
}

return loggingInterceptor
}

@Singleton
@Provides
fun provideOkHttpClient(httpLoggingInterceptor: HttpLoggingInterceptor): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(httpLoggingInterceptor)
.connectTimeout(2, TimeUnit.SECONDS)
.readTimeout(2, TimeUnit.SECONDS)
.build()
}

@Named("TestBaseUrl")
@Singleton
@Provides
fun provideBaseUrlTest(): String =
"http://localhost:8080/"

@Singleton
@Provides
fun provideRetrofit(@Named("TestBaseUrl") baseUrl: String, okHttpClient: OkHttpClient?): Retrofit {
return Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient!!)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
}
}

我的 Activity 生成器

@Module
abstract class ActivityBuilder {
@ContributesAndroidInjector(modules = [ActivityModule::class])
abstract fun injectIntoHomeActivity(): ForecastActivity

@ContributesAndroidInjector(modules = [ActivityModule::class, ForecastModule::class])
abstract fun injectIntoForecastFragment(): ForecastFragment
}

我的主要 Activity

class ForecastActivity : AppCompatActivity(), ForecastView, RetryListener, LocationUtilsListener {

companion object {
const val WEATHER_FORECAST_KEY = "weatherForecast"
}

@Inject
lateinit var forecastPresenter: ForecastPresenter

@Inject
lateinit var location: LocationUtils

private var fragmentManager: FragmentManager? = null

override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
}
}

我的仪器测试

@RunWith(AndroidJUnit4::class)
class ForecastActivityAndroidTest {
@Inject
lateinit var okHttpClient: OkHttpClient

@get:Rule
val okHttpIdingResourceRule = OkHttpIdingResourceRule(InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as AndroidTestGoWeatherApplication)

@get:Rule
val activityRule = ActivityTestRule(ForecastActivity::class.java, false, false)

private val mockWebserver: MockWebServer by lazy {
MockWebServer()
}

@Before
fun setUp() {
val testApplication =
InstrumentationRegistry.getInstrumentation().targetContext.applicationContext
as AndroidTestGoWeatherApplication

DaggerAndroidTestGoWeatherPresentationComponent
.builder()
.applicationModule(TestGoWeatherApplicationModule())
.create(testApplication)
.inject(testApplication)

mockWebserver.start(8080)
}

@After
fun tearDown() {
mockWebserver.shutdown()
}

@Test
fun should_load_five_day_forecast() {
loadFromResources("json/fivedayforecast.json")
mockWebserver.enqueue(MockResponse().setBody(loadFromResources("json/fivedayforecast.json")))

ActivityScenario.launch(ForecastActivity::class.java)

/* do some testing here *
}
}

提前致谢

最佳答案

我认为您正在以错误的方式将 OkHttpClient 依赖项注入(inject)到 OkHttpIdingResourceRule 中。

来自 Dagger 2 文档:

Constructor injection is preferred whenever possible...

你拥有 OkHttpIdingResourceRule 所以你真的应该在这里进行构造函数注入(inject)。

通过将构造函数更改为如下所示,允许 Dagger 为您构造 OkHttpIdingResourceRule:

class OkHttpIdingResourceRule @Inject constructor(application: Application, okHttpClient: OkHttpClient)

由于 OkHttpClient 已经在您的对象图中,我会将 OkHttpIdingResourceRule 注入(inject)您的测试 而不是 OkHttpClient

综上所述,我认为您的代码的其他部分仍然存在一些问题,但如果不运行它并亲自查看错误,我无法确认它们。例如,如果您计划以这种方式注入(inject)此测试,那么您必须在测试组件上使用这样的方法:

void inject(ForecastActivityAndroidTest 测试);

编辑:

我再次查看了您的规则,看起来您真正感兴趣的是注入(inject) IdlingResource。如果是这种情况,您应该将构造函数更改为如下所示:

class OkHttpIdingResourceRule @Inject constructor(idlingRes: IdlingResource)

从那里您可以做的是在您的 TestNetworkModule 中创建一个为您创建它的配置方法:

@Provides 
IdlingResource providesIdlingResource(OkHttpClient okHttpClient {
return OkHttp3IdlingResource.create("okhttp", okHttpClient)
}

关于android - 为仪器测试注入(inject) espresso 规则的依赖项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56704449/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com