Slide 1

Slide 1 text

Let's write test code of RxJava!! 1 ~a road to write test using RxJava successfully @sasami! 1

Slide 2

Slide 2 text

what steps of writing test code...?! 2

Slide 3

Slide 3 text

Steps of writing test code 1. write test function 2. run test 3. test passed!!!!! 3

Slide 4

Slide 4 text

Steps of writing test code 1. write test function 2. run test 3. test passed!!!!! ...finish? →There are some cases tests are passed without actually testing...!(especially for RxJava") 4

Slide 5

Slide 5 text

Case1 5

Slide 6

Slide 6 text

@Test fun checkoutValidations_should_be_VALID_if_hugaProcessor_is_0() { viewModel.checkoutValidations.subscribe { status -> status == CheckoutViewModel.ValidationStatus.VALID } viewModel.hugaProcessor.onNext(0) whenever(service.observeHoge()).thenReturn(Flowable.just(mock())) } 6

Slide 7

Slide 7 text

This test will pass!!!!! 7

Slide 8

Slide 8 text

! 8

Slide 9

Slide 9 text

What are problems? 4 using subscribe() method 4 subscribe() runs asynchronously even in the test code 4 an assertion inside subscribe() is occurred after evaluating test function 9

Slide 10

Slide 10 text

How to solve this? 4 use testSubscriber() 4 use Observable.test() method 10

Slide 11

Slide 11 text

4 use testSubscriber() val testSubscriber = TestSubscriber() viewModel.checkoutValidations.subscribe(testSubscriber) testSubscriber .assertNoErrors() .assertValue(CheckoutViewModel.ValidationStatus.VALID) 11

Slide 12

Slide 12 text

4 use Observable.test() method viewModel.checkoutValidations .test() .assertNoErrors() .assertNotComplete() .assertValue(CheckoutViewModel.ValidationStatus.VALID) 12

Slide 13

Slide 13 text

Case2 @Mock private lateinit var hugaProcessor: BehaviorProcessor @Test fun `checkoutValidations should have VALID status if hugaProcessor is 0`() { val testSubscriber = TestSubscriber() viewModel.checkoutValidations.subscribe(testSubscriber) viewModel.hugaProcessor.onNext(0) testSubscriber .assertNoErrors() .assertNotComplete() .assertValue(CheckoutViewModel.ValidationStatus.VALID) } 13

Slide 14

Slide 14 text

Case2 @Mock private lateinit var youPay: BehaviorProcessor @Test fun `checkoutValidations should have VALID status if hugaProcessor is 0`() { val testSubscriber = TestSubscriber() viewModel.checkoutValidations.subscribe(testSubscriber) viewModel.hugaProcessor.onNext(0) testSubscriber .assertNoErrors() .assertNotComplete() .assertValue(CheckoutViewModel.ValidationStatus.VALID) } This test is still failed...! 14

Slide 15

Slide 15 text

@Mock private lateinit var hugaProcessor: BehaviorProcessor Mocking BehaviorProcessor...? 15

Slide 16

Slide 16 text

what are problems? 4 check instance of BehaviorProcessor exists 4 If the instance is mocked, onNext() does not emit any value 16

Slide 17

Slide 17 text

How to solve this? private val hugaProcessor: BehaviorProcessor = BehaviorProcessor.create() 17

Slide 18

Slide 18 text

Case3 @Test fun callSomeObsevable_should_be_true_if_postTransaction_is_executed() { .... viewModel.callSomeObsevable.subscribe { result -> Assert.assertTrue(result) } viewModel.postTransaction(itemId).test() .assertSubscribed() .assertNoErrors() .assertComplete() } →we want to make sure callSomeObsevable emits true if postTransaction() is called successfully. 18

Slide 19

Slide 19 text

@Test fun callSomeObsevable_should_be_true_if_postTransaction_is_executed() { .... viewModel.callSomeObsevable.test() .assertNoErrors() .assertComplete() .assertValue(true) viewModel.postTransaction(itemId).test() .assertSubscribed() .assertNoErrors() .assertComplete() } → We change it like the above like Case1. 19

Slide 20

Slide 20 text

@Test fun callSomeObsevable_should_be_true_if_postTransaction_is_executed() { .... viewModel.callSomeObsevable.test() .assertNoErrors() .assertComplete() .assertValue(true) viewModel.postTransaction(itemId).test() .assertSubscribed() .assertNoErrors() .assertComplete() } This test code still fails...! 20

Slide 21

Slide 21 text

What are problems? 4 test() method also runs synchronously. So we have to care about the order of the code. 4 So postTransaction() method does not call when assertValue of the first stream is called. 21

Slide 22

Slide 22 text

How to fix this? @Test fun callSomeObsevable_should_be_true_if_postTransaction_is_executed() { .... val testSubscriber = viewModel.callSomeObsevable.test() viewModel.postTransaction(itemId).test() .assertSubscribed() .assertNoErrors() .assertComplete() testSubscriber .assertNoErrors() .assertComplete() .assertValue(true) } →before calling postTransaction, we need to subscribe observable function first. 22

Slide 23

Slide 23 text

Overview! 4 Use TestSubscriber() 4 don't mock BehaviorProcessor if you want to get from value from it. 4 care about order of the code where subscriber is subscribed 23

Slide 24

Slide 24 text

These problems are fixed by this pr...!! 24

Slide 25

Slide 25 text

thanks!! 25