При использовании Mockito.verify (), вместо того, чтобы просто проверять, вызвана ли функция на макетируемом объекте, вызывается метод из реального объекта - PullRequest
0 голосов
/ 07 июня 2019

Я пишу свой первый модульный тест для модели представления. Я имею в виду пример GithubBrowserArchitectureComponents. Я проверяю, выполняет ли функция, которая устанавливает значение для оперативных данных, функцию, вызываемую в карте переключателей для этих динамических данных из класса репозитория. Для этого я использую функцию Mocktio.verify, в этой функции я передаю параметр, который является ложным объектом для класса Repository, и проверяю, вызывается ли метод getPosts. Но я обнаружил, что вместо проверки вызова он фактически вызывает метод. Принимая во внимание, что один в образце не

Я также использую Dagger 2, так что я подозревал, что хранилище внедряется, а не имитируется, и поэтому, как показано в примере, я изменил testInstrumentationRunner на пользовательский, который использует другой класс приложения, т.е. TestApp

@RunWith(JUnit4::class)
class PostViewModelTest {
    private val testContext = TestCoroutineContext()

    @ExperimentalCoroutinesApi
    @get:Rule
    val coroutinesDispatcherRule = ViewModelScopeMainDispatcherRule(testContext)

    @Rule
    @JvmField
    val instantTaskExecutorRule = InstantTaskExecutorRule()

    private var repository = mock(PostRepository::class.java)
    private var appExecutor = mock(AppExecutors::class.java)
    private var postDao = mock(PostDao::class.java)

    private val postViewModel = PostViewModel(postDao, repository, appExecutor)


    @Test
    fun fetchWhenObserved(){
        postViewModel.showPosts("a", "b")
        postViewModel.posts.observeForever(mock())
        verify(repository).getPosts("a", "b")
    }

}

build.gradle

defaultConfig {
        applicationId "com.example.test"
        minSdkVersion 16
        targetSdkVersion 28
        multiDexEnabled true
        versionCode 3
        versionName "3.0"
        testInstrumentationRunner "com.example.test.util.MyTestRunner"
        vectorDrawables.useSupportLibrary = true
    }

MyTestRunner

/**
 * Custom runner to disable dependency injection.
 */
open class MyTestRunner : AndroidJUnitRunner() {
    override fun newApplication(cl: ClassLoader, className: String, context: Context): Application {
        return super.newApplication(cl, TestApp::class.java.name, context)
    }
}

PostViewModel

class PostViewModel @Inject
constructor(var postDao: PostDao,
            var repository: PostRepository,
            var appExecutors: AppExecutors
): ViewModel(){
    private val showPosts = MutableLiveData<Pair<String, String>>()

  // Get Post Live Data
    var posts: LiveData<PagedList<Post>> = Transformations.switchMap(showPosts) { groupIdToUserId ->
        repository.getPosts(groupIdToUserId.first, groupIdToUserId.second)
    }

fun showPosts(groupId: String, userId: String) {
        showPosts.value = groupId to userId
}
}

Репозиторий

open class PostRepository @Inject constructor(
    private var db: AppDatabase,
    private var postDao: PostDao,
    private var appExecutors: AppExecutors,
    private var apiService: ApiService,
    private var user: User
) {
fun getPosts(groupId: String, userId: String): LiveData<PagedList<Post>> {
        val factory = postDao.allPosts(groupId)
        factory.create()
        val boundaryCallback = PostBoundaryCallback(groupId, userId, postDao, apiService,  appExecutors)
        return LivePagedListBuilder(factory, 10)
            .setBoundaryCallback(boundaryCallback)
            .setFetchExecutor(appExecutors.diskIO())
            .build()
    }
}

1 Ответ

0 голосов
/ 10 июня 2019

Модульное тестирование - это тестирование отдельного блока кода, некоторые из ваших тестов - это тестирование соединений между различными классами. Это нормально, но это интеграционный тест, а не модульный тест.

Для проверки модулей необходимо проверить входы и выходы. Например, входные параметры метода и выходное возвращаемое значение.

Поэтому для вашей ViewModel вы бы хотели только проверить, что вызов вашего showPosts метода присваивает переданные входные данные LiveData. Вам нужно будет смоделировать LiveData и убедиться, что метод был вызван с вашим вводом.

Отдельно вы должны проверить свой репозиторий, передав входные данные и убедившись, что возвращенные LiveData соответствуют вашим ожиданиям. (Лично я не вернул бы LiveData из репозитория, я бы вернул ваше значение и поместил его в LiveData внутри viewmodel, но это ваш выбор).

Как только вы пройдете эти два теста, вы проверили оба устройства. Если затем вы захотите создать интеграционный тест (проверяющий, что liveata обновляется, когда ваш репозиторий запускает свой код, а система наблюдает за результатами), это дает меньшую выгоду, поскольку вы тестируете системный код, а не свой собственный. Это также было бы более грязным (как вы выяснили) и более хрупким для изменений.

Надеюсь, что это направит вас в правильном направлении, даже если это не кодирующий ответ. :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...