首页 > 解决方案 > 注入假改造服务以在 AndroidTest 中使用

问题描述

我有一个对象 EventLogger,用于存储和转发事件,它有一个可注入的改造 api:

object EventLogger {

...

private var apiInstance: EventLoggingService? = null

 /**
 * Inject the api provider
 */
fun setApi(eventLoggingService: EventLoggingService?) {
    Log.d(TAG, "Api set")
    apiInstance = eventLoggingService
}

/**
 * Get the injected api
 */
fun getApi(): EventLoggingService? = apiInstance

fun send() {
   
    // eventsToSend will be populated into local var from database

    getApi()?.logEvents(EventLoggingRequest(eventsToSend))?.retry(getRetryCount())
            ?.subscribeOn(Schedulers.io())
            ?.onErrorComplete()
            ?.subscribe({ onSuccessfulSync(eventsToSend, devicesToSend, commentsToSend) }, { Log.d(TAG, "error on sending ${eventsToSend.size} events")})

 }

  fun onSuccessfulSync(eventsToSend: List<LoggedEvent>) {
 
       // remove synced events from database

  } 

将被伪造的改造服务:

interface EventLoggingService {

@POST("v1/system/events")
   fun logEvents(
        @Body eventLoggingRequest: EventLoggingRequest
   ): Single<String>
}

在我的 AndroidTest 中:

@RunWith(AndroidJUnit4::class)
class EventLoggerAndroidTest {

...

@Test
fun testSend() {

// populate fake events

EventLogger.setApi(SucceedingEventService())
EventLogger.send()

// assert events removed from database

}

class FailingEventService : EventLoggingService {
    override fun logEvents(eventLoggingRequest: EventLoggingRequest): Single<String> {
        println("${eventLoggingRequest.events.size} events sent to failing service")
        return Single.error(TimeoutException())
    }

}

class SucceedingEventService : EventLoggingService {
    override fun logEvents(eventLoggingRequest: EventLoggingRequest): Single<String> {
        println("${eventLoggingRequest.events.size} events sent to succeeding service")
        return Single.create {
            it.onSuccess("")
        }
    }
}

由于断言错误和此堆栈跟踪,此测试失败:

I/System.out: 2 events sent to succeeding service
E/TestRunner: failed: pageData(com.doctella.doc.events.EventLoggerAndroidTest)
    ----- begin exception -----
W/System.err: io.reactivex.rxjava3.exceptions.CompositeException: 2 exceptions occurred. 
W/System.err:     at io.reactivex.rxjava3.internal.operators.maybe.MaybeCallbackObserver.onError(MaybeCallbackObserver.java:85)
W/System.err:     at io.reactivex.rxjava3.internal.operators.maybe.MaybePeek$MaybePeekObserver.onErrorInner(MaybePeek.java:147)
W/System.err:     at io.reactivex.rxjava3.internal.operators.maybe.MaybePeek$MaybePeekObserver.onSuccess(MaybePeek.java:117)
W/System.err:     at io.reactivex.rxjava3.internal.operators.maybe.MaybeOnErrorComplete$OnErrorCompleteMultiObserver.onSuccess(MaybeOnErrorComplete.java:68)
W/System.err:     at io.reactivex.rxjava3.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.onSuccess(SingleSubscribeOn.java:68)
W/System.err:     at io.reactivex.rxjava3.internal.operators.flowable.FlowableSingleSingle$SingleElementSubscriber.onComplete(FlowableSingleSingle.java:114)
W/System.err:     at io.reactivex.rxjava3.internal.operators.flowable.FlowableRetryPredicate$RetrySubscriber.onComplete(FlowableRetryPredicate.java:104)
W/System.err:     at io.reactivex.rxjava3.internal.subscriptions.DeferredScalarSubscription.complete(DeferredScalarSubscription.java:135)
W/System.err:     at io.reactivex.rxjava3.internal.operators.single.SingleToFlowable$SingleToFlowableObserver.onSuccess(SingleToFlowable.java:62)
W/System.err:     at io.reactivex.rxjava3.internal.operators.single.SingleCreate$Emitter.onSuccess(SingleCreate.java:68)
E/TestRunner: java.lang.AssertionError: expected:<1> but was:<3>
        at org.junit.Assert.fail(Assert.java:89)
        at org.junit.Assert.failNotEquals(Assert.java:835)
        at org.junit.Assert.assertEquals(Assert.java:120)
        at org.junit.Assert.assertEquals(Assert.java:146)
        at com.doctella.doc.events.EventLoggerAndroidTest$pageData$$inlined$use$lambda$1.execute(EventLoggerAndroidTest.kt:328)
        at io.realm.Realm.executeTransaction(Realm.java:1537)
        at com.doctella.doc.events.EventLoggerAndroidTest.pageData(EventLoggerAndroidTest.kt:323)
        at java.lang.reflect.Method.invoke(Native Method)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at androidx.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:80)
        at androidx.test.internal.runner.junit4.statement.RunAfters.evaluate(RunAfters.java:61)
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
        at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
        at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
        at androidx.test.ext.junit.runners.AndroidJUnit4.run(AndroidJUnit4.java:154)
        at org.junit.runners.Suite.runChild(Suite.java:128)
        at org.junit.runners.Suite.runChild(Suite.java:27)
        at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
        at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
        at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
        at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:395)
        at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2209)
E/TestRunner: ----- end exception -----
W/System.err:     at com.doctella.doc.events.EventLoggerAndroidTest$SucceedingEventService$logEvents$1.subscribe(EventLoggerAndroidTest.kt:416)
W/System.err:     at io.reactivex.rxjava3.internal.operators.single.SingleCreate.subscribeActual(SingleCreate.java:40)
        at io.reactivex.rxjava3.core.Single.subscribe(Single.java:4813)
W/System.err:     at io.reactivex.rxjava3.internal.operators.single.SingleToFlowable.subscribeActual(SingleToFlowable.java:37)
W/System.err:     at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:15750)
        at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:15696)
W/System.err:     at io.reactivex.rxjava3.internal.operators.flowable.FlowableRetryPredicate$RetrySubscriber.subscribeNext(FlowableRetryPredicate.java:124)
W/System.err:     at io.reactivex.rxjava3.internal.operators.flowable.FlowableRetryPredicate.subscribeActual(FlowableRetryPredicate.java:42)
W/System.err:     at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:15750)
W/System.err:     at io.reactivex.rxjava3.internal.operators.flowable.FlowableSingleSingle.subscribeActual(FlowableSingleSingle.java:39)
W/System.err:     at io.reactivex.rxjava3.core.Single.subscribe(Single.java:4813)
        at io.reactivex.rxjava3.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89)
W/System.err:     at io.reactivex.rxjava3.core.Scheduler$DisposeTask.run(Scheduler.java:614)
W/System.err:     at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:65)
        at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:56)
W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
W/System.err:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:919)
W/System.err:   ComposedException 1 :
        io.mockk.MockKException: can't find stub EventLogger(object EventLogger)
W/System.err:     at io.mockk.impl.stub.StubRepository.stubFor(StubRepository.kt:16)
        at io.mockk.impl.recording.states.AnsweringState.call(AnsweringState.kt:13)
W/System.err:     at io.mockk.impl.recording.CommonCallRecorder.call(CommonCallRecorder.kt:53)
W/System.err:     at io.mockk.impl.stub.MockKStub.handleInvocation(MockKStub.kt:263)
        at io.mockk.impl.instantiation.JvmMockFactoryHelper$mockHandler$1.invocation(JvmMockFactoryHelper.kt:25)
W/System.err:     at io.mockk.proxy.android.advice.Advice$handle$1.call(Advice.kt:77)
W/System.err:     at com.doctella.doc.events.EventLogger.getTAG(Unknown Source:33)
        at com.doctella.doc.events.EventLogger$send$2.accept(EventLogger.kt:185)
W/System.err:     at com.doctella.doc.events.EventLogger$send$2.accept(EventLogger.kt:15)
        at io.reactivex.rxjava3.internal.operators.maybe.MaybePeek$MaybePeekObserver.onSuccess(MaybePeek.java:114)
W/System.err:     at io.reactivex.rxjava3.internal.operators.maybe.MaybeOnErrorComplete$OnErrorCompleteMultiObserver.onSuccess(MaybeOnErrorComplete.java:68)
W/System.err:     at io.reactivex.rxjava3.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.onSuccess(SingleSubscribeOn.java:68)
W/System.err:     at io.reactivex.rxjava3.internal.operators.flowable.FlowableSingleSingle$SingleElementSubscriber.onComplete(FlowableSingleSingle.java:114)
I/TestRunner: finished: pageData(com.doctella.doc.events.EventLoggerAndroidTest)
W/System.err:     at io.reactivex.rxjava3.internal.operators.flowable.FlowableRetryPredicate$RetrySubscriber.onComplete(FlowableRetryPredicate.java:104)
W/System.err:     at io.reactivex.rxjava3.internal.subscriptions.DeferredScalarSubscription.complete(DeferredScalarSubscription.java:135)
W/System.err:     at io.reactivex.rxjava3.internal.operators.single.SingleToFlowable$SingleToFlowableObserver.onSuccess(SingleToFlowable.java:62)
W/System.err:     at io.reactivex.rxjava3.internal.operators.single.SingleCreate$Emitter.onSuccess(SingleCreate.java:68)
W/System.err:     at com.doctella.doc.events.EventLoggerAndroidTest$SucceedingEventService$logEvents$1.subscribe(EventLoggerAndroidTest.kt:416)
        at io.reactivex.rxjava3.internal.operators.single.SingleCreate.subscribeActual(SingleCreate.java:40)
W/System.err:     at io.reactivex.rxjava3.core.Single.subscribe(Single.java:4813)
W/System.err:     at io.reactivex.rxjava3.internal.operators.single.SingleToFlowable.subscribeActual(SingleToFlowable.java:37)
        at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:15750)
W/System.err:     at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:15696)
        at io.reactivex.rxjava3.internal.operators.flowable.FlowableRetryPredicate$RetrySubscriber.subscribeNext(FlowableRetryPredicate.java:124)
W/System.err:     at io.reactivex.rxjava3.internal.operators.flowable.FlowableRetryPredicate.subscribeActual(FlowableRetryPredicate.java:42)
W/System.err:     at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:15750)
        at io.reactivex.rxjava3.internal.operators.flowable.FlowableSingleSingle.subscribeActual(FlowableSingleSingle.java:39)
W/System.err:     at io.reactivex.rxjava3.core.Single.subscribe(Single.java:4813)
W/System.err:     at io.reactivex.rxjava3.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89)
        at io.reactivex.rxjava3.core.Scheduler$DisposeTask.run(Scheduler.java:614)
W/System.err:     at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:65)
W/System.err:     at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:56)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
W/System.err:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
W/System.err:     at java.lang.Thread.run(Thread.java:919)
      ComposedException 2 :
        io.mockk.MockKException: can't find stub EventLogger(object EventLogger)
W/System.err:     at io.mockk.impl.stub.StubRepository.stubFor(StubRepository.kt:16)
        at io.mockk.impl.recording.states.AnsweringState.call(AnsweringState.kt:13)
W/System.err:     at io.mockk.impl.recording.CommonCallRecorder.call(CommonCallRecorder.kt:53)
        at io.mockk.impl.stub.MockKStub.handleInvocation(MockKStub.kt:263)
W/System.err:     at io.mockk.impl.instantiation.JvmMockFactoryHelper$mockHandler$1.invocation(JvmMockFactoryHelper.kt:25)
W/System.err:     at io.mockk.proxy.android.advice.Advice$handle$1.call(Advice.kt:77)
        at com.doctella.doc.events.EventLogger.getTAG(EventLogger.kt:16)
        at com.doctella.doc.events.EventLogger$send$4.accept(EventLogger.kt:188)
W/System.err:     at com.doctella.doc.events.EventLogger$send$4.accept(EventLogger.kt:15)
W/System.err:     at io.reactivex.rxjava3.internal.operators.maybe.MaybeCallbackObserver.onError(MaybeCallbackObserver.java:82)
W/System.err:     at io.reactivex.rxjava3.internal.operators.maybe.MaybePeek$MaybePeekObserver.onErrorInner(MaybePeek.java:147)
W/System.err:     at io.reactivex.rxjava3.internal.operators.maybe.MaybePeek$MaybePeekObserver.onSuccess(MaybePeek.java:117)
W/System.err:     at io.reactivex.rxjava3.internal.operators.maybe.MaybeOnErrorComplete$OnErrorCompleteMultiObserver.onSuccess(MaybeOnErrorComplete.java:68)
W/System.err:     at io.reactivex.rxjava3.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.onSuccess(SingleSubscribeOn.java:68)
W/System.err:     at io.reactivex.rxjava3.internal.operators.flowable.FlowableSingleSingle$SingleElementSubscriber.onComplete(FlowableSingleSingle.java:114)
W/System.err:     at io.reactivex.rxjava3.internal.operators.flowable.FlowableRetryPredicate$RetrySubscriber.onComplete(FlowableRetryPredicate.java:104)
W/System.err:     at io.reactivex.rxjava3.internal.subscriptions.DeferredScalarSubscription.complete(DeferredScalarSubscription.java:135)
        at io.reactivex.rxjava3.internal.operators.single.SingleToFlowable$SingleToFlowableObserver.onSuccess(SingleToFlowable.java:62)
W/System.err:     at io.reactivex.rxjava3.internal.operators.single.SingleCreate$Emitter.onSuccess(SingleCreate.java:68)
W/System.err:     at com.doctella.doc.events.EventLoggerAndroidTest$SucceedingEventService$logEvents$1.subscribe(EventLoggerAndroidTest.kt:416)
W/System.err:     at io.reactivex.rxjava3.internal.operators.single.SingleCreate.subscribeActual(SingleCreate.java:40)
W/System.err:     at io.reactivex.rxjava3.core.Single.subscribe(Single.java:4813)
        at io.reactivex.rxjava3.internal.operators.single.SingleToFlowable.subscribeActual(SingleToFlowable.java:37)
W/System.err:     at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:15750)
W/System.err:     at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:15696)
W/System.err:     at io.reactivex.rxjava3.internal.operators.flowable.FlowableRetryPredicate$RetrySubscriber.subscribeNext(FlowableRetryPredicate.java:124)
        at io.reactivex.rxjava3.internal.operators.flowable.FlowableRetryPredicate.subscribeActual(FlowableRetryPredicate.java:42)
W/System.err:     at io.reactivex.rxjava3.core.Flowable.subscribe(Flowable.java:15750)
W/System.err:     at io.reactivex.rxjava3.internal.operators.flowable.FlowableSingleSingle.subscribeActual(FlowableSingleSingle.java:39)
W/System.err:     at io.reactivex.rxjava3.core.Single.subscribe(Single.java:4813)
        at io.reactivex.rxjava3.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89)
W/System.err:     at io.reactivex.rxjava3.core.Scheduler$DisposeTask.run(Scheduler.java:614)
W/System.err:     at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:65)
W/System.err:     at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:56)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
W/System.err:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:919)

标签: androidretrofitrx-javamockk

解决方案


推荐阅读