0

I believe there is some big gap in my understanding about RxJava

suppose we have this interface:

 interface SecretInterface {
    fun getSecretKey(): Single<Int>
  }

  interface Vault {
    fun openSecret(): Single<String>
  }

and then I have this test:

 @Test
  fun should_check_on_this() {
    val mockSecret = mock<SecretInterface> {
      on { this.getSecretKey() }.thenReturn(Single.just(1), Single.just(2),
          Single.just(3))
    }

    val mockVault = mock<Vault> {
      on { this.openSecret() }.thenReturn(Single.error(Exception("no can do")),
          Single.just("secret opened"))
    }

    val complexStuff = mockSecret.getSecretKey().doOnSuccess {
      System.err.println("onSuccess secret top $it")
    }.flatMap {
      mockVault.openSecret()
    }.retryWhen {
      it.flatMapSingle {
        mockSecret.getSecretKey().doOnSuccess { System.err.println("onSuccess secret bottom: $it") }
      }
    }

    val test = complexStuff.test()
    test.assertValue { it == "secret opened" }
    verify(mockSecret, Times(3)).getSecretKey()
  }

the test failed, because mockSecret.getSecretKey() invocated only twice, but in output:

onSuccess secret top 1
onSuccess secret bottom: 2
onSuccess secret top 1

org.mockito.exceptions.verification.TooFewActualInvocations: 
secretInterface.getSecretKey();
Wanted 3 times:

things that I can not understand is:

    -It's already resubscribed, but how come still using old value?
    -How I can make it, that every time I resubscribed always return the latest value?
  in this case it should return 3 not 1.

thank you

  • You are asserting the method invocations (e.g. mockSecret.getSecretKey()). There are two method invoctions, one at the beginning and one in retryWhen. Because the observable in retryWhen emits a value, a resubscribe happens. The method #getSecretKey is not invoced again, because the observable was already assembled. First getSecretKey is subsribed to and emits 1, the value is processed by flatMap openSecret, which errors. RetryWhen invokes getSecretKey. A resubscribe happens to captured observable. – Sergej Isbrecht May 28 '20 at 17:11
  • ... Once again emits 1, it is passed through flatMap, another method invoke happens on #openSecret, which returns "secret opened". You can avoid it by using Observable.defer { mockSecret.getSecretKey() } – Sergej Isbrecht May 28 '20 at 17:15

0 Answers0