Сначала вы должны разделить тесты записи для самого фрагмента и тесты для модели представления и живых данных.
Поскольку вы хотите написать тест для фрагмента в зависимости от модели представления Живые данные , затем я думаю, что решение состоит в том, чтобы смоделировать модель представления (или хранилище, от которого зависит модель представления) и запустить ваш фрагмент с использованием FragmentScenario и протестировать его. Как то, что сделано в этой кодовой метке .
Редактировать: на основе вашего нового предоставленного кода
Сначала я внесу некоторые изменения в ваш код, чтобы сделать он может работать и тестироваться (этот код является просто кодом, который выполняется и предназначен только для тестирования, а не является правильно сформированным и хорошо написанным кодом):
MyFragment:
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ListView
import androidx.annotation.VisibleForTesting
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider.Factory
import androidx.lifecycle.ViewModelProviders
class MyFragment : Fragment() {
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
lateinit var myViewModel: MyViewModel
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
lateinit var myListView: ListView
override fun onAttach(context: Context) {
super.onAttach(context)
val FACTORY = object : Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return MyViewModel() as T
}
}
myViewModel =
ViewModelProviders.of(this, FACTORY).get(MyViewModel::class.java)
myListView = ListView(context)
myListView.adapter = MyCustomadapter(context, listOf("a", "b", "c"))
}
val items1 = listOf("a", "b", "c")
val items2 = listOf("1", "2")
val items3 = listOf("a1", "a2", "a3")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
when (myViewModel.status.value) {
"status1" ->
setListContent(items1)
"status2" ->
setListContent(items2)
"status3" ->
setListContent(items3)
else -> setListContent(items1)
}
return View(context)
}
private fun setListContent(itemsList: List<String>) {
myListView.adapter = MyCustomadapter(context!!, itemsList)
}
}
MyCustomadapter:
import android.content.Context
import android.database.DataSetObserver
import android.view.View
import android.view.ViewGroup
import android.widget.ListAdapter
class MyCustomadapter(private val context: Context, private val itemsList: List<String>) : ListAdapter {
override fun isEmpty(): Boolean {
return itemsList.isEmpty()
}
override fun getView(p0: Int, p1: View?, p2: ViewGroup?): View {
return View(context)
}
override fun registerDataSetObserver(p0: DataSetObserver?) {
}
override fun getItemViewType(p0: Int): Int {
return 1
}
override fun getItem(p0: Int): Any {
return itemsList[p0]
}
override fun getViewTypeCount(): Int {
return 3
}
override fun isEnabled(p0: Int): Boolean {
return true
}
override fun getItemId(p0: Int): Long {
return 0
}
override fun hasStableIds(): Boolean {
return true
}
override fun areAllItemsEnabled(): Boolean {
return true
}
override fun unregisterDataSetObserver(p0: DataSetObserver?) {
}
override fun getCount(): Int {
return itemsList.size
}
}
MyViewModel:
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class MyViewModel : ViewModel() {
var status = MutableLiveData<String>()
}
В приведенном выше коде я использовал аннотацию @VisibleForTesting для возможности тестирования приватных полей. [Но я рекомендую не делать этого, а вместо этого использовать методы publi c или компоненты пользовательского интерфейса для проверки поведения кода. Поскольку вы не предоставили здесь никакого компонента пользовательского интерфейса, у меня нет другого простого выбора для тестирования вашего кода].
Теперь мы добавляем зависимости в build.gradle модулей приложения:
testImplementation 'junit:junit:4.12'
debugImplementation 'androidx.fragment:fragment-testing:1.1.0'
testImplementation 'androidx.test.ext:junit:1.1.1'
testImplementation 'org.robolectric:robolectric:4.3.1'
testImplementation 'androidx.arch.core:core-testing:2.1.0'
junit : для чисто модульного тестирования ['pure' означает, что вы не можете использовать android связанный код в своих тестах junit]. Нам всегда нужна эта библиотека для написания наших android тестов.
фрагментное тестирование : для использования FragmentScenario . Для во избежание проблемы стиля robolectri c мы используем 'debugImplementation' вместо 'testImplementation'.
androidx.test.ext: junit : для использования AndroidJUnit4.
robolectri c: мы используем robolectri c здесь для запуска android инструментальных тестов на JVM - локально ( вместо запуска на android эмуляторе или физическом устройстве).
androidx.arch.core: core-testing : мы используем это для тестирования живых данных
Для возможности использования android ресурсов в robolectri c нам нужно добавить опцию теста в приложение build.gradle:
android {
...
testOptions {
unitTests {
includeAndroidResources = true
}
}
}
И, наконец, мы пишем простой тест :
[поместите этот тест в исходный набор тестов, а не в androidTest. Также вы можете создать тестовый файл для своего кода, нажав Ctrl + Shift + T в android studio, или щелкнув правой кнопкой мыши на имени класса и нажав generate> Test ... и выбрав 'test' source source set]:
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.fragment.app.testing.launchFragment
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class MyFragmentTest {
@get:Rule
var instantExecutorRule = InstantTaskExecutorRule()
@Test
fun changingViewModelValue_ShouldSetListViewItems() {
val scenario = launchFragment<MyFragment>()
scenario.onFragment { fragment ->
fragment.myViewModel.status.value = "status1"
assert(fragment.myListView.adapter.getItem(0) == "a")
}
}
}
В приведенном выше тесте мы протестировали настройку элементов списка, установив значение данных в реальном времени. InstantTaskExecutorRule предназначен для гарантии того, что значение данных в реальном времени будет проверено предсказуемым образом (как объяснено здесь ).

Если вы хотите протестировать свои компоненты пользовательского интерфейса (например, тестировать отображаемые элементы на экране) с такими библиотеками, как Espresso или другие, сначала добавьте их зависимость в gradle, а затем измените launchFragment<MyFragment>()
на launchFragmentInContainer<MyFragment>()
, как описано здесь .