54002


## 概要

RxJavaのFlowableを返して尚且つそれぞれ開始・成功・失敗時に別々の値を返すメソッドのテストを書きたいのですが、テストコード上では開始時の結果しか取得できないため成功と失敗時のテストが出来なくて困っています。  
この場合、どのようなテストコードが適切かどなたかご教示いただけるとありがたいです。

### 使用環境

  * AndroidStudio3.3.2
  * spek1.1.5
  * mockk1.9.3
  * RxJava2.2.3

### 現時点でわかっていること

  * 開始時の結果しか取れない。
  * 調べた資料では `awaitTerminalEvent`で 「 `onCompleted()` もしくは `onError()` が呼ばれるまで待つ」 とあったが、使用するとテストが終了しない。 
    * <https://hydrakecat.hatenablog.jp/entry/2016/12/12/RxJava_%E3%81%AE%E3%83%86%E3%82%B9%E3%83%88%281%29%3A_TestSubscriber%2C_test%28%29%2C_TestScheduler>
  * テストコードにて引数を指定して onNext() を使用すると成功時の値は取れるがテストとして意味を成さない

### テスト結果

[code]

    java.lang.AssertionError: Values at position 0 differ; Expected: Success(data=[TaskList(id=1, name=todo, tasks=[Task(id=1, name=aaaaa, status=DONE), Task(id=2, name=aaaaa, status=TODO), Task(id=2, name=aaaaa, status=TODO), Task(id=2, name=aaaaa, status=TODO), Task(id=3, name=aaaaa, status=TODO)])]) (class: Success), Actual: Progress(value=true) (class: Progress) (latch = 1, values = 1, errors = 0, completions = 0, timeout!, disposed!)
    
[/code]

## 実装コード

[code]

    fun getTaskLists(): Flowable<Result<List<TaskList>>> {
            // repository.loadTaskListAndTasksByDB()の結果はモックしている
            return repository.loadTaskListAndTasksByDB()
                    .map {
                        TaskListTranslator.toTodoLists(it)
                    }
                    .toFlowable()
                    .compose { item ->
                        item
                                .map { Result.success(it) } // 成功
                                .onErrorReturn { Result.failure(it) } // 失敗
                                .startWith(Result.progress()) // 開始
                                .subscribeOn(schedulerProvider.io())
                                .observeOn(schedulerProvider.ui())
                    }
        }
    
[/code]

※ toFlowable以下の行は実際には拡張関数にしています。

  * <https://github.com/syo-sa1982/ToDo4Android/blob/new/usecase/app/src/main/kotlin/com/syousa1982/todo4android/domain/usecase/ToDoUseCase.kt>
  * <https://github.com/syo-sa1982/ToDo4Android/blob/new/usecase/app/src/main/kotlin/com/syousa1982/todo4android/util/extention/ResultRxExt.kt>

## テストコード

[code]

    @RunWith(JUnitPlatform::class)
    class ToDoUseCaseSpec : Spek({
        val taskListRepository: ITaskListRepository by lazy {
            mockk<ITaskListRepository>()
        }
    
        val schedulerProvider = TestSchedulerProvider()
    
        val todoUseCase: ToDoUseCase by lazy {
            ToDoUseCase(taskListRepository, schedulerProvider)
        }
        // repository.loadTaskListAndTasksByDB()の結果をモック
        every { taskListRepository.loadTaskListAndTasksByDB() } answers {
            val taskListAndTasks = TaskListAndTasks()
            taskListAndTasks.taskList = TaskListEntity(1, "todo")
            taskListAndTasks.tasks = listOf(
                    TaskEntity(1, 1, "aaaaa", Task.Status.DONE.value.toLowerCase()),
                    TaskEntity(2, 1, "aaaaa", Task.Status.TODO.value.toLowerCase()),
                    TaskEntity(3, 1, "aaaaa", Task.Status.TODO.value.toLowerCase())
            )
            Single.create {
                listOf(taskListAndTasks)
            }
        }
    
        describe("ToDoUseCase") {
            val expectedValue = Result.success(listOf(
                    TaskList(1, "todo", listOf(
                            Task(1, "aaaaa", Task.Status.DONE),
                            Task(2, "aaaaa", Task.Status.TODO),
                            Task(3, "aaaaa", Task.Status.TODO)
                    ))
            ))
            // ここで期待値と比較しているが、Result.Progress()しか取れないためテストが通らない
            todoUseCase
                    .getTaskLists()
                    .test()
                    .assertValue(expectedValue)
        }
    
    
    })
    
[/code]

<https://github.com/syo-
sa1982/ToDo4Android/blob/new/usecase/app/src/test/kotlin/com/syousa1982/todo4android/domain/ToDoUseCaseSpec.kt>


CC BY-SA 4.0
2019-04-07T11:02:21.750
53995
2019-04-08T00:42:59.417
2019-04-07T12:29:39.780
17065
17065
question
android kotlin reactivex
RxJavaでFlowableを返すメソッドのテストの書き方について


[assertValue](http://reactivex.io/RxJava/javadoc/io/reactivex/observers/BaseTestConsumer.html#assertValue-
io.reactivex.functions.Predicate-) はonNextによる値が1度だけ流れてくる時に利用するメソッドです。  
最初に`Result.Progress`が流れて次に目的の値が流れてくることをテストしたいならば、[assertValues](http://reactivex.io/RxJava/javadoc/io/reactivex/observers/BaseTestConsumer.html#assertValues-T...-)
を使ってみてください。

[code]

    val expectedValue = Result.success(listOf(
        TaskList(1, "todo", listOf(
            Task(1, "aaaaa", Task.Status.DONE),
            Task(2, "aaaaa", Task.Status.TODO),
            Task(3, "aaaaa", Task.Status.TODO)
        ))
    ))
    
    todoUseCase
        .getTaskLists()
        .test()
        .assertValues(Result.Progress(), expectedValue)
    
[/code]

最初に`Result.Progress`が来ることはわかっていてその検証を行う必要がないなら、`skip`で飛ばしてしまうのもありかと思います。

[code]

    todoUseCase
        .getTaskLists()
        .skip(1)
        .test()
        .assertValue(expectedValue)
    
[/code]

* * *

それと、モック部分のコードについてですが、

[code]

    Single.create {
        listOf(taskListAndTasks)
    }
    
[/code]

ここの `create` は `fromCallable` （もしくは `just`） の間違いではないでしょうか？


CC BY-SA 4.0
2019-04-07T23:27:20.803
54002
2019-04-08T00:42:59.417
2019-04-08T00:42:59.417
915
915
53995
answer