android studio 3.4.1
dagger-android 2.21
我正在使用Dagger-android将OKHttpClient注入浓缩咖啡规则中。但是还没有找到一种方法,我尝试了很多不同的事情。
这是我正在使用的规则,我正在尝试将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()
}
}
我的ActivityBuilder
@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 *
}
}
非常感谢
答案 0 :(得分:2)
我认为您正在以错误的方式将OkHttpClient
依赖项注入OkHttpIdingResourceRule
的过程。
来自匕首2文档:
尽可能使用构造函数注入...
您拥有OkHttpIdingResourceRule
,因此您实际上应该在此处进行构造函数注入。
通过将构造函数更改为以下形式,允许Dagger为您构造OkHttpIdingResourceRule
:
class OkHttpIdingResourceRule @Inject constructor(application: Application, okHttpClient: OkHttpClient)
由于OkHttpClient
已经存在于您的对象图中,因此我将OkHttpIdingResourceRule
注入到测试{em> 中的OkHttpClient
所有这些,我认为您在代码的其他部分仍然存在一些问题,但是如果没有运行它并且自己看到错误,我无法确认它们。例如,如果您打算以这种方式注入该测试,则必须在测试组件上使用如下方法:
void inject(ForecastActivityAndroidTest test);
编辑:
我再次查看了您的规则,看来您真正感兴趣的是注入IdlingResource
。如果是这种情况,则应将构造函数更改为如下形式:
class OkHttpIdingResourceRule @Inject constructor(idlingRes: IdlingResource)
从那里可以做的是在TestNetworkModule
中创建一个配置方法,为您创建该方法:
@Provides
IdlingResource providesIdlingResource(OkHttpClient okHttpClient {
return OkHttp3IdlingResource.create("okhttp", okHttpClient)
}