distinctUntilChanged を使ったらテストが上手くいかなかった

このテストは通る :white_check_mark:

```kotlin
class SampleViewModel : ViewModel() {

    private val _liveData = MutableLiveData<Boolean>()
    val liveData: LiveData<Boolean>
        get() = _liveData

    fun updateLiveData(bool: Boolean) {
        _liveData.value = bool
    }
}
```

```kotlin
class SampleViewModelTest {

    @get:Rule
    val rule = InstantTaskExecutorRule()

    @Test
    fun testUpdateLiveData() {

        val viewModel = SampleViewModel()

        assertThat(viewModel.liveData.value).isNull()

        viewModel.updateLiveData(true)

        assertThat(viewModel.liveData.value).isTrue()
    }
}
```

<br>

しかし、liveDataを`distinctUntilChanged`を用いるように修正すると、`assertThat(viewModel.liveData.value).isTrue()`のところで通らなくなる :x:

```kotlin
class SampleViewModel : ViewModel() {

    private val _liveData = MutableLiveData<Boolean>()
    val liveData: LiveData<Boolean>
        get() = _liveData.distinctUntilChanged() // 修正

    fun updateLiveData(bool: Boolean) {
        _liveData.value = bool
    }
}
```

# 原因 １

`distinctUntilChanged`の実装を見てみると、MediatorLiveDataを新たに生成し、ソースを追加して、LiveDataとして返している。
つまり、先のコードでは`liveData`を取得しようとする度に、別のLiveDataが返ってきていた。
また、ソースのLiveData（`_liveData`）の値に関わらず、初期値が`null`のMediatorLiveDataが生成されているので、先のテストでは常に`viewModel.liveData.value == null`となる

```java:Transformations.java
    ...

    @MainThread
    @NonNull
    public static <X> LiveData<X> distinctUntilChanged(@NonNull LiveData<X> source) {
        final MediatorLiveData<X> outputLiveData = new MediatorLiveData<>();
        outputLiveData.addSource(source, new Observer<X>() {

            boolean mFirstTime = true;

            @Override
            public void onChanged(X currentValue) {
                final X previousValue = outputLiveData.getValue();
                if (mFirstTime
                        || (previousValue == null && currentValue != null)
                        || (previousValue != null && !previousValue.equals(currentValue))) {
                    mFirstTime = false;
                    outputLiveData.setValue(currentValue);
                }
            }
        });
        return outputLiveData;
    }

    ...
```

### 対応

ゲッターを用いず、フィールドに保持する。

```kotlin
class SampleViewModel : ViewModel() {

    private val _liveData = MutableLiveData<Boolean>()
    val liveData: LiveData<Boolean> = _liveData.distinctUntilChanged() // 修正

    fun updateLiveData(bool: Boolean) {
        _liveData.value = bool
    }
}
```

# 原因 ２

`addSource`の実装を見てみると、最後に`hasActiveObservers`でMediatorLiveDataがアクティブなObserverを持っているかどうかを確認し、持っている場合のみ`plug`を呼び出している。

```java:MediatorLiveData.java
    ...

    @MainThread
    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
        Source<S> e = new Source<>(source, onChanged);
        Source<?> existing = mSources.putIfAbsent(source, e);
        if (existing != null && existing.mObserver != onChanged) {
            throw new IllegalArgumentException(
                    "This source was already added with the different observer");
        }
        if (existing != null) {
            return;
        }
        if (hasActiveObservers()) {
            e.plug();
        }
    }

    ...
```

`plug`の実装を見てみると、ソースのLiveDataを`observe`している。
つまり、MediatorLiveData（`liveData`）が、アクティブなObserverによって`observe`されていない場合、ソースのLiveData（`_liveData`）の値の変更を受け取らない実装になっている。
そのため、先のコードでは`liveData`の値は更新されず、初期値である`null`のままとなる。

```java:MediatorLiveData.java
    ...

    private static class Source<V> implements Observer<V> {
        final LiveData<V> mLiveData;
        final Observer<? super V> mObserver;
        int mVersion = START_VERSION;

        Source(LiveData<V> liveData, final Observer<? super V> observer) {
            mLiveData = liveData;
            mObserver = observer;
        }

        void plug() {
            mLiveData.observeForever(this);
        }

        void unplug() {
            mLiveData.removeObserver(this);
        }

        @Override
        public void onChanged(@Nullable V v) {
            if (mVersion != mLiveData.getVersion()) {
                mVersion = mLiveData.getVersion();
                mObserver.onChanged(v);
            }
        }
    }

    ...
```

### 対応

テスト内で`liveData`を`observe`する。

```kotlin
class SampleViewModelTest {

    @get:Rule
    val rule = InstantTaskExecutorRule()

    @Test
    fun testUpdateLiveData() {

        val viewModel = SampleViewModel()
        viewModel.liveData.observeForever {} // 追加

        assertThat(viewModel.liveData.value).isNull()

        viewModel.updateLiveData(true)

        assertThat(viewModel.liveData.value).isTrue()
    }
}
```

# まとめ

MutableLiveDataを用いる時に、ゲッターを利用することもあると思うが、`distinctUntilChanged`を使う場合は、フィールドで保持した方が良い。

また、`distinctUntilChanged`や`map`、`switchMap`など、MediatorLiveDataを用いる時は、`observe`しないと値が更新されない。