Spec-Zone.ru › Kotlin 2

Тестирование мультиплатформенного приложения − руководство

В этом руководстве вы узнаете, как создавать, настраивать и запускать тесты в приложениях Kotlin Multiplatform.

Тесты в мультиплатформенных проектах можно разделить на две категории:

  • Тесты для общего кода. Эти тесты можно запускать на любой платформе с помощью любого поддерживаемого фреймворка.

  • Тесты для платформозависимого кода. Они необходимы для проверки платформозависимой логики. Для них используется платформозависимый фреймворк, который может предоставить дополнительные возможности, например более богатый API и широкий набор проверок.

В мультиплатформенных проектах поддерживаются обе категории. Сначала в этом руководстве вы узнаете, как настроить, создать и запустить модульные тесты для общего кода в простом проекте Kotlin Multiplatform. Затем вы рассмотрите более сложный пример, для которого нужны тесты как для общего, так и для платформозависимого кода.

Предполагается, что вы знакомы со следующими темами:

  • Структура проекта Kotlin Multiplatform. Если это не так, перед началом пройдите это руководство.

  • Основы популярных фреймворков для модульного тестирования, например JUnit.

Тестирование простого мультиплатформенного проекта

Создание проекта

  1. В кратком руководстве выполните инструкции по настройке среды для разработки Kotlin Multiplatform.

  2. В IntelliJ IDEA выберите Файл | Создать | Проект.

  3. На панели слева выберите Kotlin Multiplatform.

  4. В окне Новый проект укажите следующие значения:

    • Имя: KMP testing

    • Идентификатор проекта: kmp.project.testing

  5. Выберите целевую платформу Android. Если вы используете Mac, выберите также iOS. Обязательно выберите параметр Не делиться пользовательским интерфейсом.

  6. Снимите флажок Добавить тесты и нажмите Создать.

    Create simple multiplatform project

Написание кода

В каталоге sharedLogic/src/commonMain/kotlin создайте пакет common.example.search. В этом пакете создайте файл Kotlin Grep.kt со следующей функцией:

fun grep(lines: List<String>, pattern: String, action: (String) -> Unit) {
    val regex = pattern.toRegex()
    lines.filter(regex::containsMatchIn)
        .forEach(action)
}

Эта функция имитирует команду grep в UNIX. Функция принимает строки текста, шаблон в виде регулярного выражения и функцию, которая вызывается при каждом совпадении строки с шаблоном.

Добавление тестов

Теперь протестируем общий код. Важную роль в этом играет набор исходного кода для общих тестов, у которого в качестве зависимости подключена библиотека API kotlin.test.

  1. Убедитесь, что в файле sharedLogic/build.gradle.kts есть зависимость от библиотеки kotlin.test:

    sourceSets {
       //...
       commonTest.dependencies {
           implementation(libs.kotlin.test)
       }
    }
    
  2. В наборе исходного кода commonTest хранятся все общие тесты. Создайте в проекте каталог с таким же именем:

    1. Щёлкните правой кнопкой мыши каталог sharedLogic/src и выберите Создать | Каталог. В IDE появится список вариантов.

    2. Начните вводить путь commonTest/kotlin, чтобы сузить список вариантов, а затем выберите его:

    Creating common test directory
  3. В каталоге commonTest/kotlin создайте пакет common.example.search.

  4. В этом пакете создайте файл Grep.kt и добавьте в него следующий модульный тест:

    import kotlin.test.Test
    import kotlin.test.assertContains
    import kotlin.test.assertEquals
    
    class GrepTest {
        companion object {
            val sampleData = listOf(
                "123 abc",
                "abc 123",
                "123 ABC",
                "ABC 123"
            )
        }
    
        @Test
        fun shouldFindMatches() {
            val results = mutableListOf<String>()
            grep(sampleData, "[a-z]+") {
                results.add(it)
            }
    
            assertEquals(2, results.size)
            for (result in results) {
                assertContains(result, "abc")
            }
        }
    }
    

Как видите, импортируемые аннотации и проверки не зависят ни от платформы, ни от фреймворка. При запуске этого теста платформозависимый фреймворк предоставит средство запуска тестов.

Знакомство с API kotlin.test

Библиотека kotlin.test предоставляет не зависящие от платформы аннотации и проверки, которые можно использовать в тестах. Такие аннотации, как Test, соответствуют аннотациям выбранного фреймворка или их ближайшим аналогам.

Проверки выполняются с помощью реализации интерфейса Asserter. Этот интерфейс определяет различные проверки, которые обычно выполняются при тестировании. API предоставляет реализацию по умолчанию, но обычно используется реализация, специфичная для конкретного фреймворка.

Например, на JVM поддерживаются фреймворки JUnit 4, JUnit 5 и TestNG. На Android вызов assertEquals() может привести к вызову asserter.assertEquals(), где объект asserter является экземпляром JUnit4Asserter. На iOS реализация типа Asserter по умолчанию используется вместе со средством запуска тестов Kotlin/Native.

Запуск тестов

Запустить тест можно следующими способами:

  • Запустить тестовую функцию shouldFindMatches() с помощью значка Запустить на полосе рядом с кодом.

  • Запустить файл теста через его контекстное меню.

  • Запустить тестовый класс GrepTest с помощью значка Запустить на полосе рядом с кодом.

Также можно воспользоваться сочетанием клавиш ⌃ ⇧ F10/Ctrl+Shift+F10. Независимо от выбранного способа, вы увидите список целевых платформ для запуска теста:

Run test task

Для варианта android тесты запускаются с помощью JUnit 4. Для варианта iosSimulatorArm64 компилятор Kotlin обнаруживает аннотации для тестирования и создаёт тестовый бинарный файл, который запускается собственным средством запуска тестов Kotlin/Native.

Пример вывода после успешного запуска теста:

Test output

Работа с более сложными проектами

Написание тестов для общего кода

Вы уже создали тест для общего кода с помощью функции grep(). Теперь рассмотрим более сложный тест общего кода с классом CurrentRuntime. Этот класс содержит сведения о платформе, на которой выполняется код. Например, при локальном запуске модульных тестов Android на JVM в нём могут быть значения «OpenJDK» и «17.0».

Экземпляр CurrentRuntime нужно создать, указав название платформы и её версию в виде строк; версия является необязательной. Если версия указана, достаточно привести начальное число строки, если оно есть.

  1. В каталоге commonMain/kotlin создайте пакет org.kmp.testing.

  2. В этом пакете создайте файл CurrentRuntime.kt и добавьте в него следующую реализацию:

    class CurrentRuntime(val name: String, rawVersion: String?) {
        companion object {
            val versionRegex = Regex("^[0-9]+(\\.[0-9]+)?")
        }
    
        val version = parseVersion(rawVersion)
    
        override fun toString() = "$name version $version"
    
        private fun parseVersion(rawVersion: String?): String {
            val result = rawVersion?.let { versionRegex.find(it) }
            return result?.value ?: "unknown"
        }
    }
    
  3. В каталоге commonTest/kotlin создайте пакет org.kmp.testing.

  4. В этом пакете создайте файл CurrentRuntimeTest.kt и добавьте в него следующий тест, не зависящий от платформы и фреймворка:

    import kotlin.test.Test
    import kotlin.test.assertEquals
    
    class CurrentRuntimeTest {
        @Test
        fun shouldDisplayDetails() {
            val runtime = CurrentRuntime("MyRuntime", "1.1")
            assertEquals("MyRuntime version 1.1", runtime.toString())
        }
    
        @Test
        fun shouldHandleNullVersion() {
            val runtime = CurrentRuntime("MyRuntime", null)
            assertEquals("MyRuntime version unknown", runtime.toString())
        }
    
        @Test
        fun shouldParseNumberFromVersionString() {
            val runtime = CurrentRuntime("MyRuntime", "1.2 Alpha Experimental")
            assertEquals("MyRuntime version 1.2", runtime.toString())
        }
    
        @Test
        fun shouldHandleMissingVersion() {
            val runtime = CurrentRuntime("MyRuntime", "Alpha Experimental")
            assertEquals("MyRuntime version unknown", runtime.toString())
        }
    }
    

Этот тест можно запустить любым из доступных в IDE способов.

Добавление платформозависимых тестов

Для краткости и простоты здесь используется механизм ожидаемых и фактических объявлений. В более сложном коде лучше использовать интерфейсы и фабричные функции.

Теперь, когда вы научились писать тесты для общего кода, рассмотрим написание платформозависимых тестов для Android и iOS.

Чтобы создать экземпляр CurrentRuntime, объявите функцию в общем файле CurrentRuntime.kt следующим образом:

expect fun determineCurrentRuntime(): CurrentRuntime

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

Для Android

  1. В каталоге androidMain/kotlin создайте пакет org.kmp.testing.

  2. В этом пакете создайте файл AndroidRuntime.kt и добавьте в него фактическую реализацию ожидаемой функции determineCurrentRuntime():

    actual fun determineCurrentRuntime(): CurrentRuntime {
        val name = System.getProperty("java.vm.name") ?: "Android"
    
        val version = System.getProperty("java.version")
    
        return CurrentRuntime(name, version)
    }
    
  3. Создайте каталог для тестов внутри каталога sharedLogic/src:

    1. Щёлкните правой кнопкой мыши каталог sharedLogic/src и выберите Создать | Каталог. В IDE появится список вариантов.

    2. Начните вводить путь androidHostTest/kotlin, чтобы сузить список вариантов, а затем выберите его:

      Creating Android test directory
  4. В каталоге androidHostTest/kotlin создайте пакет org.kmp.testing.

  5. В этом пакете создайте файл AndroidRuntimeTest.kt и добавьте в него следующий тест Android. Чтобы тест прошёл, укажите фактическое имя и версию среды выполнения (но также полезно посмотреть, как тест завершается с ошибкой):

    import kotlin.test.Test
    import kotlin.test.assertContains
    import kotlin.test.assertEquals
    
    class AndroidRuntimeTest {
        @Test
        fun shouldDetectAndroid() {
            val runtime = determineCurrentRuntime()
            assertContains(runtime.name, "OpenJDK")
            assertEquals(runtime.version, "21.0")
        }
    }
    

Может показаться странным, что тест Android запускается на локальной JVM. Это объясняется тем, что такие тесты выполняются на текущем компьютере как локальные модульные тесты. Как описано в документации Android Studio, они отличаются от инструментированных тестов, которые запускаются на устройстве или эмуляторе.

В проект можно добавить и другие типы тестов. Чтобы узнать об инструментированных тестах, ознакомьтесь с этим руководством Touchlab.

Для iOS

  1. В каталоге iosMain/kotlin создайте каталог org.kmp.testing.

  2. В этом каталоге создайте файл IOSRuntime.kt и добавьте в него фактическую реализацию ожидаемой функции determineCurrentRuntime():

    import kotlin.experimental.ExperimentalNativeApi
    import kotlin.native.Platform
    
    @OptIn(ExperimentalNativeApi::class)
    actual fun determineCurrentRuntime(): CurrentRuntime {
        val name = Platform.osFamily.name.lowercase()
        return CurrentRuntime(name, null)
    }
    
  3. Создайте новый каталог в каталоге sharedLogic/src:

    1. Щёлкните правой кнопкой мыши каталог sharedLogic/src и выберите Создать | Каталог. В IDE появится список вариантов.

    2. Начните вводить путь iosTest/kotlin, чтобы сузить список вариантов, а затем выберите его:

  4. В каталоге iosTest/kotlin создайте каталог org.kmp.testing.

  5. В этом каталоге создайте файл IOSRuntimeTest.kt и добавьте в него следующий тест iOS:

    import kotlin.test.Test
    import kotlin.test.assertEquals
    
    class IOSRuntimeTest {
        @Test
        fun shouldDetectOS() {
            val runtime = determineCurrentRuntime()
            assertEquals(runtime.name, "ios")
            assertEquals(runtime.version, "unknown")
        }
    }
    

Запуск нескольких тестов и анализ отчётов

Теперь у вас есть код для общего кода, реализаций Android и iOS, а также соответствующие тесты. Структура каталогов проекта должна выглядеть примерно так:

Whole project structure

Отдельные тесты можно запускать из контекстного меню или с помощью сочетания клавиш. Ещё один способ — использовать задачи Gradle. Например, если запустить задачу Gradle allTests, все тесты проекта будут выполнены соответствующими средствами запуска:

Gradle test tasks

При запуске тестов, помимо вывода в IDE, создаются HTML-отчёты. Их можно найти в каталоге sharedLogic/build/reports/tests:

HTML reports for multiplatform tests

Запустите задачу allTests и изучите созданные отчёты:

  • Файл allTests/index.html содержит объединённые отчёты об общих тестах и тестах iOS (тесты iOS зависят от общих тестов и выполняются после них).

  • Папки testDebugUnitTest и testReleaseUnitTest содержат отчёты для обоих вариантов сборки Android по умолчанию. (В настоящее время отчёты о тестах Android не объединяются автоматически с отчётом allTests.)

HTML report for multiplatform tests

Правила использования тестов в мультиплатформенных проектах

Теперь вы умеете создавать, настраивать и запускать тесты в приложениях Kotlin Multiplatform. При работе с тестами в будущих проектах помните о следующем:

  • При написании тестов для общего кода используйте только мультиплатформенные библиотеки, например kotlin.test. Добавляйте зависимости в набор исходного кода commonTest.

  • Тип Asserter из API kotlin.test следует использовать только косвенно. Хотя экземпляр Asserter доступен, в тестах его использовать не нужно.

  • Всегда используйте только API библиотеки тестирования. К счастью, компилятор и IDE не позволяют использовать функциональность, специфичную для фреймворка.

  • Для запуска тестов в commonTest неважно, какой фреймворк вы используете, однако рекомендуется запускать тесты с каждым предполагаемым фреймворком, чтобы убедиться в правильности настройки среды разработки.

  • Учитывайте физические различия. Например, инерция прокрутки и значения трения отличаются в зависимости от платформы и устройства, поэтому одинаковая скорость прокрутки может привести к разным положениям прокрутки. Всегда тестируйте компоненты на целевой платформе, чтобы убедиться в ожидаемом поведении.

  • При написании тестов для платформозависимого кода можно использовать возможности соответствующего фреймворка, например аннотации и расширения.

  • Тесты можно запускать как из IDE, так и с помощью задач Gradle.

  • При запуске тестов HTML-отчёты о тестировании создаются автоматически.

Что дальше?

  • Изучите структуру мультиплатформенных проектов в разделе «Знакомство со структурой мультиплатформенного проекта».

  • Познакомьтесь с Kotest — ещё одним мультиплатформенным фреймворком для тестирования из экосистемы Kotlin. Kotest позволяет писать тесты в разных стилях и поддерживает дополнительные подходы к обычному тестированию, включая тестирование на основе данных и свойств.

15 мая 2026 г.
Сборка готовых нативных бинарных файловПубликация приложения

© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/multiplatform/multiplatform-run-tests.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API