Ошибка модульного тестирования LiveData при использовании postValue в блоке init - PullRequest
0 голосов
/ 11 октября 2018

Я пытаюсь написать модульный тест для модели представления с использованием оперативных данных.

LoginViewModel.kt

class LoginViewModel @Inject constructor(
    val context: Context
): ViewModel() {
    val username = MutableLiveData<String>()
    val password = MutableLiveData<String>()
    val isLoginButtonEnabled = MediatorLiveData<Boolean>().apply {
        fun combineLatest(): Boolean {
            return !(username.value.isNullOrEmpty() || password.value.isNullOrEmpty())
        }
        addSource(username) { this.value = combineLatest() }
        addSource(password) { this.value = combineLatest() }
    }

    init {
        username.postValue("test")
        password.postValue("test")
    }
}

LoginViewModelTest.kt

@RunWith(MockitoJUnitRunner::class)
class LoginViewModelTest {
    @Rule
    @JvmField
    val instantTaskExecutorRole = InstantTaskExecutorRule()

    private val context = mock(Context::class.java)
    private val loginViewModel = LoginViewModel(context)

    @Test
    fun loginButtonDisabledOnEmptyUsername() {
        val observer = mock<Observer<Boolean>>()
        loginViewModel.isLoginButtonEnabled.observeForever(observer)
        loginViewModel.username.postValue("")

        verify(observer).onChanged(false)
    }
}

Мой модульный тест выдает следующее исключение в строке username.postValue("test"):

java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See http://g.co/androidstudio/not-mocked for details.

Тем не менее InstantTaskExecutorRule должен обеспечивать контекст выполнения при использовании оперативных данных.он не работает при инициализации реальных данных в init -блоке.Если пропустить init -блок, он работает как нужно, но мне нужна возможность инициализировать переменные данных в реальном времени.

Есть ли способ заставить инициализацию данных в реальном времени работать при модульном тестировании моделей просмотра?

1 Ответ

0 голосов
/ 12 октября 2018

Мне удалось протестировать мой ViewModel, который использовал LiveData, используя упомянутое правило - InstantTaskExecutorRule.Но в моем случае объявление правила val было немного другим:

@Suppress("unused")
@get:Rule
val instantTaskExecutorRule: InstantTaskExecutorRule = InstantTaskExecutorRule()

Edit:

@Before
@Throws(Exception::class)
fun prepare() {
    MockitoAnnotations.initMocks(this)
}

Edit2:

По какой-то странной причине я не могу воспроизвести это:Кроме того, я думаю, что проблема может быть в том, как вы инициализируете вашу ViewModel -

private val loginViewModel = LoginViewModel(context)

Я предполагаю, что он инициализируется слишком рано, поэтому его блок инициализации также вызывается слишком рано.Может быть, разумно создать его методом @Before?Нравится:

private lateinit var viewModel: LoginViewModel

@Before
@Throws(Exception::class)
fun prepare() {
    loginViewModel = LoginViewModel(context)
}
...