【发布时间】:2019-06-27 04:20:58
【问题描述】:
android studio 3.4.1
dagger-android 2.21
我正在使用 dagger-android 将我的 OKHttpClient 注入到 espresso 规则中。但是还没有找到方法来做到这一点,我尝试了很多不同的事情。
这是我正在使用的规则,我正在尝试将 okHttpClient 注入其中
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()
}
}
我的活动构建器
@Module
abstract class ActivityBuilder {
@ContributesAndroidInjector(modules = [ActivityModule::class])
abstract fun injectIntoHomeActivity(): ForecastActivity
@ContributesAndroidInjector(modules = [ActivityModule::class, ForecastModule::class])
abstract fun injectIntoForecastFragment(): ForecastFragment
}
我的主要活动
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 *
}
}
在此先感谢
【问题讨论】:
-
基本上我认为你从一开始就搞错了。根据您所说的,您想使用 Espresso 测试真实应用程序并使用模拟测试业务逻辑。所以我会使用
IdlingResource,直到视图加载并显示来自真实服务器的实际天气数据。 -
我正在使用 mockwebserver 来测试业务逻辑。但我想使用空闲资源,我遇到的问题是在浓缩咖啡测试中注入它。
标签: android android-espresso dagger-2