Написать модульные тесты для частного метода Presenter - PullRequest
1 голос
/ 08 июня 2019

Я пишу юнит-тесты для докладчиков проекта MVP.

class SplashPresenter {
    override fun onAttach() {
        if (dataManager.getAppLaunchFirstTime()) {
            onAppOpenFirstTime()
        } else {
            // Other logic...
        }
    }

    @VisibleForTesting
    fun onAppOpenFirstTime() {
        dataManager.setAppLaunchFirstTime(false)
        splashView.openLoginScreen()

        // May be I will add more functionalities in the future...
    }
}

Здесь у нас есть 2 подходов для написания модульного теста.

Первый подход

Проверьте непосредственно, что произойдет: openLoginScreen() & setAppLaunchFirstTime(false). Не важно, как они будут называться.

@Test
fun onAttachTest_appLaunchFirstTime() {
    Mockito.`when`(dataManager.getAppLaunchFirstTime()).thenReturn(true)

    splashPresenter.onAttach()

    verify(dataManager).setAppLaunchFirstTime(false)
    verify(splashView).openLoginScreen()
}

Второй подход

Мы используем spy() для проверки того, что будет вызван закрытый внутренний метод onAppOpenFirstTime(). Затем напишите еще один отдельный тест для onAppOpenFirstTime().

@Test
fun onAttachTest_appLaunchFirstTime() {
    `when`(dataManager.getAppLaunchFirstTime()).thenReturn(true)
    val spyPresenter = Mockito.spy(splashPresenter)

    spyPresenter.onAttach()

    verify(spyPresenter).onAppOpenFirstTime()
}

@Test
fun onAppOpenFirstTimeTest() {
    splashPresenter.onAppOpenFirstTime()

    verify(dataManager).setAppLaunchFirstTime(false)
    verify(splashView).openLoginScreen()
}

Так какой подход лучше? Какой подход сделает проект более тестируемым при расширении возможностей в будущем?

Нужно ли писать модульный тест для закрытого внутреннего метода?

Ответы [ 2 ]

1 голос
/ 13 июня 2019

(Вы спросили, какой подход сделает проект более тестируемым, но тестируемость является свойством тестируемой системы. Однако отличительным свойством комплектов тестов в этом примере является усилие по сопровождению тестового кода.).

В вашем конкретном примере второй подход делает ваши тесты излишне зависимыми от деталей реализации, которые могут измениться: есть вероятность, что вы переименуете onAppOpenFirstTime, разделите его на несколько вспомогательных функций илидаже удалите его и вставьте в onAttach.Во всех этих сценариях изменений второй подход потребует дополнительных усилий по обслуживанию, чтобы поддерживать набор тестов.

Однако я подчеркнул, что зависимость от onAppOpenFirstTime здесь не нужна.Это объясняется тем, что нет смысла использовать второй подход: первый подход, похоже, способен обнаружить те же ошибки, что и второй, тесты в первом подходе так же легко настроить, как и во втором (даже проще), и поэтомувкл.

Однако при других обстоятельствах ситуация может отличаться.Попытки сохранить комплекты юнит-тестов полностью независимыми от деталей реализации могут привести к неэффективным комплектам тестов, то есть к комплектам тестов, которые не подходят для поиска всех найденных ошибок.И поиск ошибок - одна из основных целей тестирования (см. Майерс, Бадгетт, Сандлер: Искусство тестирования программного обеспечения или Бейзер: методы тестирования программного обеспечения и многие другие).

В конце концов, ошибкив реализации.Разные реализации будут иметь разные ошибки.Подумайте о различных способах реализации функции Фибоначчи: как итеративной / рекурсивной функции, выражения закрытой формы (Moivre / Binet), справочной таблицы: каждая реализация имеет разные потенциальные ошибки.Модульное тестирование является методом тестирования в нижней части тестовой пирамиды , и все высокоуровневые тесты (интеграционные или системные тесты) менее подходят для поиска ошибок в деталях реализации.

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

1 голос
/ 08 июня 2019

Общепринято, что вы не должны проверять частные методы. Поскольку ваши закрытые методы будут вызываться некоторыми открытыми методами, вам следует проверять только открытые методы.

Вы тестируете функциональность класса, а не методы по отдельности. Вам никогда не удастся протестировать все методы в классе по отдельности, но вы всегда можете попробовать проверить функциональные возможности класса (используя открытые методы), что в конечном итоге приведет к вызову всех методов класса, как частных, так и общедоступных. достижение высокого покрытия кода.

Первый подход кажется лучше, поскольку он проверяет, чего вы хотите достичь.

...