Test
13.05.2023 | https://maxkim.eu/full-guide-to-testing-android-applications-in-2022 |
Snapshot Testing
Метод тестирования UI, при котором создаются и сравниваются “снимки” состояния интерфейса приложения. Основная идея заключается в том, чтобы сохранить изображение или структуру UI в виде “снапшота” и затем проверить, что текущий вывод совпадает с ожидаемым.
• Снапшот-тесты позволяют быстро обнаруживать изменения в UI, которые могут возникнуть в результате изменений кода или стилей.
• Упрощают тестирование сложных интерфейсов, так как позволяют фокусироваться на визуальных аспектах, а не на логике.
Синтетические тесты
Синтетические тесты в моделируют работу приложения в определенных условиях, используя заранее подготовленные данные, а не реальные пользовательские сценарии. Они фокусируются на измерении производительности, скорости выполнения операций или других метрик приложения (например, время рендеринга или загрузки), но могут не отражать реальные взаимодействия пользователей. Такие тесты полезны для оценки производительности отдельных компонентов или сценариев, но их результаты могут отличаться от показателей при реальном использовании.
JUnit
https://developer.android.com/training/testing/instrumented-tests/androidx-test-libraries/rules |
Фреймворк для написания и выполнения тестов в Java. Он является стандартным инструментом для юнит-тестирования и широко используется в разработке приложений, включая Android-приложения. JUnit позволяет создавать автоматические тесты, что способствует повышению качества кода и уменьшению количества ошибок.
public class CalculatorTest {
private Calculator calculator;
@Before
public void setUp() {
calculator = new Calculator();
}
@Test
public void testAdd() {
assertEquals(5, calculator.add(2, 3));
}
@Test
public void testSubtract() {
assertEquals(1, calculator.subtract(3, 2));
}
}
Robolectric
https://developer.android.com/training/testing/local-tests/robolectric |
Библиотека для тестирования Android-приложений, которая позволяет запускать юнит-тесты на обычной JVM без необходимости эмулятора или реального устройства. Это делает процесс тестирования быстрее и удобнее для разработчиков, так как нет необходимости ожидать загрузки эмулятора или устройства.
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [28]) // Указываем версию SDK
class MainActivityTest {
@Test
fun testActivityLaunch() {
// Запуск Activity
val activity = Robolectric.buildActivity(MainActivity::class.java).create().start().resume().get()
// Проверка, что Activity запустилась
assertNotNull(activity)
}
@Test
fun testIntent() {
val intent = Intent(ApplicationProvider.getApplicationContext(), MainActivity::class.java)
val activity = Robolectric.buildActivity(MainActivity::class.java, intent).create().get()
// Проверка, что Activity получила правильный Intent
assertEquals(activity.intent, intent)
}
}
Espresso
Библиотека для UI-тестирования Android-приложений, предоставляющая API для написания тестов, взаимодействующих с элементами интерфейса пользователя. Она позволяет имитировать пользовательские действия, проверять состояние UI-компонентов и обеспечивать синхронное выполнение тестов.
@Test
fun testButtonClick() {
// Найти кнопку и кликнуть по ней
onView(withId(R.id.my_button)).perform(click())
// Проверить текст на экране после нажатия
onView(withId(R.id.text_view)).check(matches(withText("Hello World!")))
}
Kotest
Мощная библиотека для тестирования на языке Kotlin, которая предоставляет различные стили для написания тестов и дополнительные утилиты для упрощения тестирования.
class SampleTest: FunSpec({
test("simple test") {
1 + 1 shouldBe 2
}
})
Kakao
Kotlin DSL для библиотеки Espresso, созданная для упрощения написания UI-тестов в Android. Kakao предоставляет удобный и читаемый синтаксис, благодаря Kotlin DSL, что делает тесты более лаконичными и простыми в поддержке.
class MainTest: KTestCase() {
@Test
fun testButtonClick() {
// Поиск кнопки и клик
KButton { withId(R.id.my_button) }.click()
// Проверка текста на экране после нажатия
KTextView { withId(R.id.text_view) }.hasText("Hello World!")
}
}
Kaspresso
Инструмент для UI-тестирования Android-приложений, который предоставляет удобный и мощный API на основе Espresso и Kakao. Он расширяет возможности стандартного Espresso, добавляя удобные функции для написания стабильных и читаемых тестов, а также упрощая работу с нестабильными элементами интерфейса.
class SimpleTest: KaspressoTestCase() {
@Test
fun testSimpleUI() = run {
step("Open the main screen") {
MainScreen {
someButton {
isVisible()
click()
}
}
}
step("Verify the next screen") {
NextScreen {
someText {
isVisible()
hasText("Expected Text")
}
}
}
}
}
Roborazzi
Библиотека для тестирования пользовательского интерфейса (UI) в Android, разработанная для упрощения и улучшения процесса визуального тестирования. Она позволяет автоматически захватывать изображения пользовательских интерфейсов приложений и сравнивать их с эталонными изображениями, что помогает выявлять изменения в интерфейсе при внесении правок в код.
class MyUITest {
@Test
fun testMyScreen() {
// Открыть экран
launchActivity<MyActivity>()
// Захватить изображение
Roborazzi.takeSnapshot("my_screen")
// Сравнить с эталоном
Roborazzi.compareSnapshot("my_screen")
}
}
Mockito
Популярная библиотека для создания моков и стаба в Java, широко используемая в тестировании. Она позволяет разработчикам имитировать поведение объектов, что упрощает тестирование бизнес-логики, обеспечивая при этом изоляцию тестируемых классов от их зависимостей.
public class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Before
public void setUp() {
MockitoAnnotations.openMocks(this); // Инициализация моков
}
@Test
public void testGetUser() {
// Настройка поведения мока
when(userRepository.findById("123")).thenReturn(new User("123", "John Doe"));
// Выполнение тестируемого метода
User user = userService.getUser("123");
// Проверка результата
assertNotNull(user);
assertEquals("John Doe", user.getName());
// Верификация взаимодействий
verify(userRepository).findById("123");
}
}
MockK
Библиотека для создания моков и стаба в Kotlin, используемая в тестировании. Она предоставляет мощные возможности для упрощения написания тестов, позволяя разработчикам легко имитировать поведение объектов и проверять взаимодействия между ними.
class UserService(private val userRepository: UserRepository) {
fun getUser(id: String): User? {
return userRepository.findById(id)
}
}
class UserServiceTest {
private val userRepository = mockk<UserRepository>()
private val userService = UserService(userRepository)
@Test
fun testGetUser() {
// Устанавливаем поведение мока
every { userRepository.findById("123") } returns User("123", "John Doe")
// Выполняем тестируемый метод
val user = userService.getUser("123")
// Проверяем результат
assertNotNull(user)
assertEquals("John Doe", user?.name)
// Проверяем взаимодействие с мок-объектом
verify { userRepository.findById("123") }
}
}
AssertJ
Библиотека для тестирования, предоставляющая удобный и выразительный API для написания ассертов в Java и Kotlin. Она значительно упрощает проверку ожидаемых результатов в тестах, делая код более читаемым и поддерживаемым.
public class ExampleTest {
@Test
public void testPerson() {
Person person = new Person("John", 25);
assertThat(person)
.isNotNull()
.hasFieldOrPropertyWithValue("name", "John")
.hasFieldOrPropertyWithValue("age", 25);
}
}
Shot
Библиотека для Android, предназначенная для создания и проверки снапшот-тестов пользовательского интерфейса.
@Test
fun myTest() {
val activity = launchActivity<MyActivity>()
activity.onView(withId(R.id.my_view)).check(matches(isDisplayed()))
shot().screenshot(activity, "my_view_snapshot")
}
Turbine
Библиотека для тестирования Kotlin Flow. Она упрощает написание тестов для Flow-потоков, предоставляя DSL для проверки эмиссий, завершений и исключений в потоках.
class ExampleTest {
@Test
fun testFlow() = runBlocking {
val flow = flow {
emit(1)
emit(2)
emit(3)
}
flow.test {
assert(awaitItem() == 1)
assert(awaitItem() == 2)
assert(awaitItem() == 3)
awaitComplete() // Ожидаем завершения потока
}
}
}
runTest
Функция из библиотеки kotlinx.coroutines
, предназначенная для упрощения тестирования кода, использующего корутины. runTest
позволяет запускать корутины в тестовом окружении, автоматически обрабатывая их задержки и выполнение, делая тесты быстрыми и надежными. Это особенно полезно для unit-тестов, где нужно протестировать функции с асинхронными операциями.
class CoroutineTest {
// Функция, которую нужно протестировать
suspend fun fetchData(): String {
delay(1000)
return "Data received"
}
@Test
fun testFetchData() = runTest {
val result = fetchData()
assertEquals("Data received", result) // Проверяем результат
}
}
Вопросы на собесе (6)
- Что такое Unit-тестирование, и почему оно важно в разработке Android приложений?
Unit-тестирование проверяет отдельные компоненты кода на корректность работы. Оно важно в Android-разработке, так как помогает выявлять ошибки на ранних этапах, улучшает качество кода и упрощает его поддержку.
- Чем интеграционные тесты отличаются от Unit-тестов?
Интеграционные тесты проверяют взаимодействие нескольких компонентов системы, тогда как Unit-тесты тестируют отдельные модули в изоляции. Интеграционные тесты помогают выявить проблемы на уровне взаимодействия, а Unit-тесты фокусируются на логике отдельных частей кода.
- Разница между Mock и Stub?
Mock создает объект для тестирования, который имитирует поведение реального объекта и проверяет взаимодействия. Stub просто возвращает предопределенные ответы, не проверяя вызовы.
- Что такое синтетические тесты?
Синтетические тесты — это тесты, которые измеряют производительность системы или приложения в специально созданных условиях, используя искусственные данные. Они помогают оценить эффективность отдельных компонентов, но не всегда отражают реальные сценарии использования.
- Какую функциональность приложения покрывать Unit-тестами?
• Бизнес-логика.
• Проверки данных.
• Вызовы API.
• Мапперы и форматтеры.
- Какую функциональность приложения покрывать UI-тестами?
• Навигацию.
• Отображение интерактивных элементов.
• Ошибки и уведомления.
• Адаптивное отображение.