Какой у тебя опыт написания тестов

Ответ

Имею опыт написания unit-тестов (JUnit, Mockito) и UI-тестов (Espresso, UI Automator).

Unit-тесты:

@Test
fun `validateEmail should return true for valid email`() {
    val validator = EmailValidator()
    assertTrue(validator.validateEmail("test@example.com"))
}

UI-тесты (Espresso):

@Test
fun loginButton_click_showsWelcomeMessage() {
    onView(withId(R.id.loginButton)).perform(click())
    onView(withText("Welcome!")).check(matches(isDisplayed()))
}

Также работал с тестированием ViewModel, LiveData, Coroutines и интеграционными тестами. Использую правило InstantTaskExecutorRule для тестирования асинхронных операций.

Ответ 18+ 🔞

А, ну ты про тесты спрашиваешь? Да, было дело, приходилось этим заниматься. Не то чтобы прям кайфовал, но понимаю, что без этого никуда — иначе потом прилетает такое, что волосы дыбом встают, ёпта.

С юнит-тестами, в принципе, всё понятно. Берёшь свой кусок кода, который не должен смотреть ни на базу, ни на сеть, ни на погоду за окном, и начинаешь его дрочить со всех сторон. Главное — изолировать его от всего мира, чтобы он был как монах в келье. Для этого Mockito — лучший друг, товарищ и брат. Хочешь, чтобы твой репозиторий возвращал пустой список? Пожалуйста — when(repository.getData()).thenReturn(emptyList()). Хочешь, чтобы он кидал исключение, как сосед сверху в три ночи? Легко. Это ж хитрая жопа, этот мокинг — можно подсунуть любой сценарий и посмотреть, не сломается ли твоя логика. Вот, например, простейший тест на валидацию email:

@Test
fun `validateEmail should return true for valid email`() {
    val validator = EmailValidator()
    assertTrue(validator.validateEmail("test@example.com"))
}

Выглядит просто, да? Но если не покрыть все кейсы — пустая строка, строка без собаки, с двумя собаками — потом получишь баг на продакшене, и будет тебе овердохуища проблем. Сам от себя охуеешь, когда поймёшь, что пропустил элементарщину.

А вот с UI-тестами — это уже ёперный театр. Espresso — мощная штука, но иногда такая капризная, ядрёна вошь. Написал тест, он на эмуляторе работает, а на реальном устройстве падает, потому что вьюха не успела прорисоваться. Приходится костылить с IdlingResource или sleep(), что само по себе пиздопроебибна. Но когда всё работает — красота. Кликнул на кнопку, проверил, что появился нужный текст. Прямо как пользователь, только автоматизированный и не спящий.

@Test
fun loginButton_click_showsWelcomeMessage() {
    onView(withId(R.id.loginButton)).perform(click())
    onView(withText("Welcome!")).check(matches(isDisplayed()))
}

С ViewModel и LiveData тоже своя специфика. Особенно когда корутины подключаются. Тут без InstantTaskExecutorRule и TestCoroutineDispatcher — просто пиши пропало. Иначе тесты будут гоняться за асинхронными задачами, как кот за лазерной указкой, и никогда не догонят. Надо всё залочить на одном потоке, чтобы было предсказуемо. Иначе волнение ебать — запустил десять раз, и три раза упало.

В общем, тестирование — это такая работа, где доверия ебать ноль. Не проверил — считай, сломал. Подозрение ебать чувствую к любому коду, который не покрыт. Хотя, конечно, иногда так лень этим заниматься, думаешь — да похуй, и так сработает. Но это путь в темный лес, чувак. Потом ночью разбудит алерт, и будешь искать, где же ты, блядь, не дописал тот самый assertFalse.