Тестирование и развитие 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 — локальная установка не требуется.
Все уроки этого курса
- Лямбда с получателем: основа DSL
- @DslMarker: предотвращение утечки получателя
- Создание типобезопасного DSL для HTML/конфигурации
- Тестирование и развитие DSL без нарушения совместимости