0Pricing
Kotlin Academy · Урок

Тестирование и развитие DSL без нарушения совместимости

Проектируйте стабильные API DSL и тестируйте их с помощью понятных блоков проверок.

«Тестирование и развитие DSL без нарушения совместимости» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.

Почему тестирование DSL отличается

DSL — это открытый API. Его изменения могут нарушить работу каждого места вызова в пользовательском коде. Тестирование DSL означает проверку как создаваемого им вывода, так и обеспечиваемой им структуры — включая проверку того, что недопустимые конструкции по-прежнему остаются ошибками компиляции.

Тестирование вывода DSL

Самый простой тест: создайте объект с помощью DSL и проверьте сформированный результат или внутреннее состояние построителя.

@Test
fun `div contains a paragraph`() {
    val result = html {
        body {
            div { p("Hi") }
        }
    }
    assertTrue(result.render().contains("<p>"))
}

Тестирование состояния построителя

Вместо проверки сформированной строки непосредственно протестируйте граф объектов построителя. Такой подход лучше переносит изменения форматирования:

@Test
fun `server config has correct port`() {
    val cfg = server {
        host = "example.com"
        port = 9090
    }
    assertEquals(9090, cfg.port)
    assertEquals("example.com", cfg.host)
}

Тестирование вложенных структур

Обойдите дерево объектов, чтобы проверить отношения вложенности:

@Test
fun `body contains one div`() {
    val page = html { body { div { } } }
    assertEquals(1, page.children
        .filterIsInstance<Body>().first()
        .children.filterIsInstance<Div>().size
    )
}

Тестирование ошибок компиляции

Нельзя напрямую протестировать ошибки компиляции с помощью модульных тестов, но можно добавить комментарии вроде // This should NOT compile, оставив ошибочный код закомментированным. В некоторых проектах используют библиотеку Kotlin Compile Testing, чтобы проверить, что определённый код НЕ компилируется.

Безопасное развитие DSL: аддитивные изменения

Добавление новых необязательных параметров со значениями по умолчанию или новых функций построителя обратно совместимо. Существующие места вызова компилируются без изменений.

// Before
fun server(block: ServerConfig.() -> Unit): ServerConfig
// After — additive: new optional feature
fun server(enableMetrics: Boolean = false, block: ServerConfig.() -> Unit): ServerConfig

Ломающее изменение: удаление или переименование

Удаление или переименование функции DSL нарушает существующие места вызова. Если переименование необходимо, предоставьте устаревший псевдоним и удалите его в будущей мажорной версии:

@Deprecated("Use database{} instead", ReplaceWith("database(block)"))
fun db(block: DbConfig.() -> Unit) = database(block)

Версионирование DSL

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

Использование @RequiresOptIn для экспериментальных возможностей DSL

Помечайте нестабильные расширения DSL аннотацией @RequiresOptIn. Пользователи явно включают их, что предотвращает случайную зависимость от возможностей, которые могут измениться:

@RequiresOptIn(message = "This DSL feature is experimental and may change")
annotation class ExperimentalDsl

@ExperimentalDsl
fun ServerConfig.enableDebug() { /*...*/ }

Делегирование свойств в DSL

DSL могут использовать делегирование свойств, чтобы требовать обязательные поля и предоставлять понятные сообщения об ошибках, когда обязательное значение отсутствует:

class Required<T> {
    private var value: T? = null
    operator fun getValue(t: Any?, p: KProperty<*>): T = value ?: error("${p.name} is required")
    operator fun setValue(t: Any?, p: KProperty<*>, v: T) { value = v }
}

Контрактное тестирование между версиями

Храните набор «эталонных» фрагментов использования DSL в виде тестов. Если рефакторинг нарушит их работу, набор тестов обнаружит это раньше пользователей. Кроме того, эти фрагменты служат актуальной документацией.

Быстрая проверка

Какой вид изменения DSL наиболее безопасен с точки зрения обратной совместимости?

Повторение: тестирование и развитие DSL

Основные выводы:

  • Тестируйте вывод DSL и состояние объектов построителя в модульных тестах
  • Аддитивные изменения (новые необязательные функции или параметры) безопасны
  • Используйте @Deprecated(ReplaceWith=...), чтобы переименовывать элементы без нарушения работы пользователей
  • Используйте @RequiresOptIn для экспериментальных возможностей DSL
  • Храните тесты эталонного использования, чтобы обнаруживать регрессии между версиями

Часто задаваемые вопросы

Урок «Тестирование и развитие DSL без нарушения совместимости» бесплатный?

Да — полный текст урока «Тестирование и развитие DSL без нарушения совместимости» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.

Чему я научусь в уроке «Тестирование и развитие DSL без нарушения совместимости»?

Проектируйте стабильные API DSL и тестируйте их с помощью понятных блоков проверок. Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Kotlin Academy?

Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Тестирование и развитие DSL без нарушения совместимости»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Kotlin Academy?

Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Лямбда с получателем: основа DSL
  2. @DslMarker: предотвращение утечки получателя
  3. Создание типобезопасного DSL для HTML/конфигурации
  4. Тестирование и развитие DSL без нарушения совместимости
← Назад к Kotlin Academy