Spec-Zone.ru › Kotlin 2

Плагин компилятора Power-assert

Плагин компилятора Kotlin Power-assert упрощает отладку, предоставляя подробные сообщения об ошибках с контекстной информацией. Он упрощает написание тестов, автоматически добавляя промежуточные значения в сообщения об ошибках. С его помощью можно понять, почему тест завершился с ошибкой, без использования сложных библиотек для проверок.

Пример сообщения, предоставляемого плагином:

Incorrect length
assert(hello.length == world.substring(1, 4).length) { "Incorrect length" }
       |     |      |  |     |               |
       |     5      |  |     "orl"           3
       "Hello"      |  "world!"
                    false

Основные возможности плагина Power-assert:

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

  • Библиотека времени выполнения: библиотека предоставляет аннотацию @PowerAssert и класс CallExplanation. Они упрощают обнаружение и настройку функций, поддерживающих Power-assert, благодаря их непосредственной интеграции с преобразованиями плагина компилятора.

  • Упрощённое тестирование: плагин автоматически генерирует информативные сообщения об ошибках, уменьшая потребность в сложных библиотеках для проверок.

  • Поддержка нескольких функций: по умолчанию плагин преобразует вызовы функции assert(), но может преобразовывать и другие функции, такие как require(), check() и assertTrue().

Подключение плагина

Gradle

Чтобы включить плагин Power-assert, настройте файл build.gradle(.kts) следующим образом:

// build.gradle.kts
plugins {
    kotlin("multiplatform") version "2.4.20"
    kotlin("plugin.power-assert") version "2.4.20"
}
// build.gradle
plugins {
    id 'org.jetbrains.kotlin.multiplatform' version '2.4.20'
    id 'org.jetbrains.kotlin.plugin.power-assert' version '2.4.20'
}

Плагин Power-assert предоставляет несколько параметров для настройки своего поведения:

  • functions содержит полные пути к функциям, вызовы которых преобразует плагин Power-assert. Если параметр не задан, плагин преобразует только вызовы kotlin.assert().

  • compilationFilter определяет, к каким компиляциям Kotlin применяется плагин Power-assert. Можно создать собственный фильтр или использовать предопределённые параметры:

    • PowerAssertCompilationFilter.TESTS применяется ко всем наборам исходного кода для тестов (по умолчанию).

    • PowerAssertCompilationFilter.ALL применяется ко всем наборам исходного кода.

    Параметр compilationFilter заменил устаревший параметр includedSourceSets, который задавал наборы исходного кода Gradle, преобразуемые плагином Power-assert. Эти параметры взаимоисключающие: если задан includedSourceSets, параметр compilationFilter игнорируется.

Чтобы настроить поведение плагина, добавьте блок powerAssert {} в файл сценария сборки:

// build.gradle.kts
powerAssert {
    functions = listOf("kotlin.assert", "kotlin.test.assertTrue", "kotlin.test.assertEquals", "kotlin.test.assertNull")
    compilationFilter = PowerAssertCompilationFilter {
        it.name in setOf("commonMain", "jvmMain", "jsMain", "nativeMain")
    }
}
// build.gradle
powerAssert {
    functions = ["kotlin.assert", "kotlin.test.assertTrue", "kotlin.test.assertEquals", "kotlin.test.assertNull"]
    compilationFilter = PowerAssertCompilationFilter {
        it.name in ["commonMain", "jvmMain", "jsMain", "nativeMain"]
    }
}

Поскольку плагин является экспериментальным, при каждой сборке приложения будут отображаться предупреждения. Чтобы скрыть их, добавьте эту аннотацию @OptIn перед объявлением блока powerAssert {}:

import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi

@OptIn(ExperimentalKotlinGradlePluginApi::class)
powerAssert {
    ...
}

Maven

Чтобы включить плагин компилятора Power-assert в проекте Maven, обновите раздел <plugin> файла kotlin-maven-plugin в файле pom.xml:

<build>
    <plugins>
        <plugin>
            <artifactId>kotlin-maven-plugin</artifactId>
            <groupId>org.jetbrains.kotlin</groupId>
            <version>2.4.20</version>
            <executions>
                <execution>
                    <id>compile</id>
                    <phase>process-sources</phase>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
                <execution>
                    <id>test-compile</id>
                    <phase>process-test-sources</phase>
                    <goals>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>

            <configuration>
                <!-- Specify the Power-assert plugin -->
                <compilerPlugins>
                    <plugin>power-assert</plugin>
                </compilerPlugins>
            </configuration>

            <!-- Add the Power-assert plugin dependency -->
            <dependencies>
                <dependency>
                    <groupId>org.jetbrains.kotlin</groupId>
                    <artifactId>kotlin-maven-power-assert</artifactId>
                    <version>2.4.20</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

Настроить функции, преобразуемые плагином Power-assert, можно с помощью параметра function. Например, можно добавить kotlin.test.assertTrue(), kotlin.test.assertEquals() и другие функции. Если параметр не задан, по умолчанию преобразуются только вызовы kotlin.assert().

Укажите этот параметр в разделе <configuration> файла kotlin-maven-plugin:

<configuration>
    <!-- Specify the functions to transform -->
    <pluginOptions>
        <option>power-assert:function=kotlin.assert</option>
        <option>power-assert:function=kotlin.test.assertTrue</option>
        <option>power-assert:function=kotlin.test.AssertEquals</option>
    </pluginOptions>
</configuration>

Использование плагина Power-assert

В этом разделе приведены примеры использования плагина компилятора Power-assert.

Полный код файла сценария сборки build.gradle.kts или pom.xml со всеми этими примерами:

// build.gradle.kts import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi plugins { kotlin("multiplatform") version "2.4.20" kotlin("plugin.power-assert") version "2.4.20" } group = "com.example" version = "1.0-SNAPSHOT" repositories { mavenCentral() } dependencies { testImplementation(kotlin("test")) } tasks.test { useJUnitPlatform() } @OptIn(ExperimentalKotlinGradlePluginApi::class) powerAssert { functions = listOf("kotlin.assert", "kotlin.test.assertEquals", "kotlin.test.assertTrue", "kotlin.test.assertNull", "kotlin.require", "com.example.AssertScope.assert") }
// build.gradle plugins { id 'org.jetbrains.kotlin.multiplatform' version '2.4.20' id 'org.jetbrains.kotlin.plugin.power-assert' version '2.4.20' } group = 'com.example' version = '1.0-SNAPSHOT' repositories { mavenCentral() } dependencies { testImplementation 'org.jetbrains.kotlin:kotlin-test' } test { useJUnitPlatform() } powerAssert { functions = [ 'kotlin.assert', 'kotlin.test.assertEquals', 'kotlin.test.assertTrue', 'kotlin.test.assertNull', 'kotlin.require', 'com.example.AssertScope.assert' ] }
<!-- pom.xml --> <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>maven-power-assert-plugin-demo</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <kotlin.code.style>official</kotlin.code.style> <kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget> </properties> <repositories> <repository> <id>mavenCentral</id> <url>https://repo1.maven.org/maven2/</url> </repository> </repositories> <build> <sourceDirectory>src/main/kotlin</sourceDirectory> <testSourceDirectory>src/test/kotlin</testSourceDirectory> <plugins> <plugin> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-plugin</artifactId> <version>2.4.20</version> <executions> <execution> <id>compile</id> <phase>compile</phase> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>test-compile</id> <phase>test-compile</phase> <goals> <goal>test-compile</goal> </goals> </execution> </executions> <configuration> <compilerPlugins> <plugin>power-assert</plugin> </compilerPlugins> <pluginOptions> <option>power-assert:function=kotlin.assert</option> <option>power-assert:function=kotlin.require</option> <option>power-assert:function=kotlin.test.assertTrue</option> <option>power-assert:function=kotlin.test.assertEquals</option> <option>power-assert:function=kotlin.test.assertNull</option> <option>power-assert:function=com.example.AssertScope.assert</option> </pluginOptions> </configuration> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-power-assert</artifactId> <version>2.4.20</version> </dependency> </dependencies> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.2</version> </plugin> <plugin> <artifactId>maven-failsafe-plugin</artifactId> <version>2.22.2</version> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.6.0</version> <configuration> <mainClass>MainKt</mainClass> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-test-junit5</artifactId> <version>2.4.20</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.10.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib</artifactId> <version>2.4.20</version> </dependency> </dependencies> </project>

Функции с аннотацией @PowerAssert

Если функция помечена аннотацией @PowerAssert, плагин Power-assert автоматически преобразует вызовы этой функции. Регистрировать её в конфигурации сборки не требуется.

Можно добавлять аннотации @PowerAssert при объявлении собственных функций для проверок или использовать библиотеки с поддержкой Power-assert, предоставляющие функции с такими аннотациями.

Чтобы получать подробные сообщения об ошибках, вызывайте функцию в проекте с включённым плагином Power-assert:

import kotlin.test.Test

data class Mascot(val name: String)

class SampleTest {

    @Test
    fun testAnnotatedFunction() {
        val subject: Any? = Mascot(name = "Unknown")
        // If assertThat() is annotated with @PowerAssert in the library,
        // the plugin transforms this call automatically
        assertThat(subject) {
            require(subject is Mascot)
            check(subject.name == "Kodee")
        }
    }
}

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

check(subject.name == "Kodee")
      |       |    |
      |       |    false
      |       "Unknown"
      Mascot(name=Unknown)

Функция assert

Рассмотрим следующий тест с функцией assert():

import kotlin.test.Test

class SampleTest {

    @Test
    fun testFunction() {
        val hello = "Hello"
        val world = "world!"
        assert(hello.length == world.substring(1, 4).length) { "Incorrect length" }
    }
}

Если запустить тест testFunction() с включённым плагином Power-assert, появится подробное сообщение об ошибке:

Incorrect length
assert(hello.length == world.substring(1, 4).length) { "Incorrect length" }
       |     |      |  |     |               |
       |     5      |  |     "orl"           3
       "Hello"      |  "world!"
                    false

Чтобы получить более полное сообщение об ошибке, всегда передавайте переменную непосредственно в качестве параметра тестовой функции. Рассмотрим следующую тестовую функцию:

class ComplexExampleTest {

    data class Person(val name: String, val age: Int)

    @Test
    fun testComplexAssertion() {
        val person = Person("Alice", 10)
        val isValidName = person.name.startsWith("A") && person.name.length > 3
        val isValidAge = person.age in 21..28
        assert(isValidName && isValidAge)
    }
}

Вывод выполненного кода не содержит достаточно информации, чтобы найти причину проблемы:

assert(isValidName && isValidAge)
       |              |
       true           false

Передайте переменную непосредственно в функцию assert():

class ComplexExampleTest {

    data class Person(val name: String, val age: Int)

    @Test
    fun testComplexAssertion() {
        val person = Person("Alice", 10)
        assert(person.name.startsWith("A") && person.name.length > 3 && person.age > 20 && person.age < 29)
    }
}

После выполнения вы получите более подробную информацию о том, что пошло не так:

assert(person.name.startsWith("A") && person.name.length > 3 && person.age > 20 && person.age < 29)
       |      |    |                  |      |    |      |      |      |   |
       |      |    true               |      |    5      true   |      10  false
       |      "Alice"                 |      "Alice"            Person(name=Alice, age=10)
       Person(name=Alice, age=10)     Person(name=Alice, age=10)

Не только функция assert

Плагин Power-assert может преобразовывать различные функции, помимо assert, которая преобразуется по умолчанию. Можно также преобразовывать такие функции, как require(), check(), assertTrue(), assertEqual() и другие, если их сигнатура позволяет передать значение типа String или () -> String в качестве последнего параметра.

Перед использованием новой функции в тесте добавьте её в файл сборки. Например, функцию require():

// build.gradle.kts
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi

@OptIn(ExperimentalKotlinGradlePluginApi::class)
powerAssert {
    functions = listOf("kotlin.assert", "kotlin.require")
}
powerAssert {
    functions = [
            'kotlin.assert',
            'kotlin.require'
    ]
}
<!-- pom.xml -->
<configuration>
    <pluginOptions>
        <option>power-assert:function=kotlin.assert</option>
        <option>power-assert:function=kotlin.require</option>
    </pluginOptions>
</configuration>

Добавив функцию, можно использовать её в тестах:

class RequireExampleTest {

    @Test
    fun testRequireFunction() {
        val value = ""
        require(value.isNotEmpty()) { "Value should not be empty" }
    }
}

В этом примере плагин Power-assert предоставляет подробную информацию о тесте, завершившемся с ошибкой:

Value should not be empty
require(value.isNotEmpty()) { "Value should not be empty" }
        |     |
        ""    false

В сообщении показаны промежуточные значения, приведшие к ошибке, что упрощает отладку.

Мягкие проверки

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

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

fun <R> assertSoftly(block: AssertScope.() -> R): R {
    val scope = AssertScopeImpl()
    val result = scope.block()
    if (scope.errors.isNotEmpty()) {
        throw AssertionError(scope.errors.joinToString("\n"))
    }
    return result
}

interface AssertScope {
    fun assert(assertion: Boolean, message: (() -> String)? = null)
}

class AssertScopeImpl : AssertScope {
    val errors = mutableListOf<String>()
    override fun assert(assertion: Boolean, message: (() -> String)?) {
        if (!assertion) {
            errors.add(message?.invoke() ?: "Assertion failed")
        }
    }
}

Добавьте эти функции в файл сборки, чтобы сделать их доступными для плагина Power-assert:

// build.gradle.kts
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi

@OptIn(ExperimentalKotlinGradlePluginApi::class)
powerAssert {
    functions = listOf("kotlin.assert", "kotlin.test.assert", "com.example.AssertScope.assert")
}
powerAssert {
    functions = [
            'kotlin.assert',
            'kotlin.test.assert',
            'com.example.AssertScope.assert'
    ]
}
<!-- pom.xml -->
<configuration>
    <pluginOptions>
        <option>power-assert:function=kotlin.assert</option>
        <option>power-assert:function=kotlin.require</option>
        <option>power-assert:function=com.example.AssertScope.assert</option>
    </pluginOptions>
</configuration>

Укажите полное имя пакета, в котором объявлена функция AssertScope.assert().

После этого её можно использовать в тестовом коде:

// Import the assertSoftly() function
import com.example.assertSoftly

class SoftAssertExampleTest1 {

    data class Employee(val name: String, val age: Int, val salary: Int)

    @Test
    fun `test employees data`() {
        val employees = listOf(
            Employee("Alice", 30, 60000),
            Employee("Bob", 45, 80000),
            Employee("Charlie", 55, 40000),
            Employee("Dave", 150, 70000)
        )

        assertSoftly {
            for (employee in employees) {
                assert(employee.age < 100) { "${employee.name} has an invalid age: ${employee.age}" }
                assert(employee.salary > 50000) { "${employee.name} has an invalid salary: ${employee.salary}" }
            }
        }
    }
}

В выводе одно за другим будут напечатаны все сообщения об ошибках функции assert():

Charlie has an invalid salary: 40000
assert(employee.salary > 50000) { "${employee.name} has an invalid salary: ${employee.salary}" }
       |        |      |
       |        40000  false
       Employee(name=Charlie, age=55, salary=40000)

Dave has an invalid age: 150
assert(employee.age < 100) { "${employee.name} has an invalid age: ${employee.age}" }
       |        |   |
       |        150 false
       Employee(name=Dave, age=150, salary=70000)

Добавление поддержки Power-assert в библиотеку

Если вы автор библиотеки, можно добавить в неё встроенную поддержку Power-assert с помощью аннотации @PowerAssert и класса CallExplanation из библиотеки среды выполнения Power-assert.

Аннотация @PowerAssert

Аннотация @PowerAssert помечает функцию как поддерживающую Power-assert. Если в проектах пользователей вашей библиотеки подключён плагин компилятора Power-assert и они вызывают ваши функции с этой аннотацией, вызовы преобразуются автоматически, без дополнительной настройки сборки.

Чтобы добавить поддержку Power-assert в библиотеку:

  1. В файле сборки подключите плагин Power-assert.

  2. Для Maven добавьте библиотеку среды выполнения Power-assert в качестве зависимости:

    <!-- pom.xml -->
    <dependencies>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-power-assert-runtime</artifactId>
            <version>2.4.20</version>
        </dependency>
    </dependencies>
    

    В Gradle эта зависимость добавляется автоматически вместе с плагином компилятора Power-assert.

  3. Добавьте аннотацию @PowerAssert к функциям для проверок:

    import kotlin.powerassert.PowerAssert
    import kotlin.powerassert.toDefaultMessage
    import kotlin.contracts.ExperimentalContracts
    import kotlin.contracts.contract
    
    @OptIn(ExperimentalContracts::class)
    @PowerAssert
    fun powerAssert(condition: Boolean, @PowerAssert.Ignore message: String? = null) {
        contract { returns() implies condition }
        if (!condition) {
            val explanation = PowerAssert.explanation
                ?: fail(message)
    
            val equalityErrors = buildList {
                for (expression in explanation.expressions) {
                    if (expression is EqualityExpression && expression.value == false) {
                        add(expression)
                    }
                }
            }
    
            val failureMessage = buildString {
                if (message?.isNotBlank() == true) appendLine(message)
                append(explanation.toDefaultMessage())
            }
    
            fail(failureMessage, equalityErrors)
        }
    }
    
    • Свойство PowerAssert.explanation предоставляет доступ к объекту CallExplanation, содержащему информацию о месте вызова.

    • Функция toDefaultMessage() формирует стандартное сообщение об ошибке Power-assert.

    • Аннотация @PowerAssert.Ignore для параметра message исключает его из сообщения об ошибке.

Плагин компилятора обнаруживает аннотацию @PowerAssert и преобразует вызовы функции во время компиляции.

Полный пример см. в проекте kotlin-test-power-assert.

Класс CallExplanation

Класс CallExplanation предоставляет подробную информацию о месте вызова, в том числе о промежуточных значениях выражений. Это позволяет динамически формировать сообщения об ошибках проверок и улучшает интеграцию с внешними инструментами.

Если функция вашей библиотеки помечена аннотацией @PowerAssert и подключён плагин компилятора, преобразование автоматически выполняется в каждом месте вызова. Свойство PowerAssert.explanation предоставляет доступ к объекту CallExplanation внутри тела функции.

Свойство PowerAssert.explanation может возвращать null, если аннотированная функция вызывается из Java, из проекта без подключённого плагина Power-assert или с помощью рефлексии.

Ниже показано, как использовать CallExplanation внутри функций с аннотацией @PowerAssert, чтобы извлечь информацию об исходном коде и сформировать собственные сообщения об ошибках:

package kotlinx.test.fluent

import kotlin.powerassert.PowerAssert
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract

@PowerAssert
fun AssertScope<*>.check(condition: Boolean) {
    if (!condition) {
        val explanation = PowerAssert.explanation
        val message = if (explanation == null) null else {
            val conditionArg = explanation.arguments.last()!!
            val source = explanation.source.substring(conditionArg.startOffset, conditionArg.endOffset)
            "Condition failed: $source"
        }
        collect(message, explanation)
    }
}

@OptIn(ExperimentalContracts::class)
@PowerAssert
fun AssertScope<*>.require(condition: Boolean) {
    contract { returns() implies condition }
    if (!condition) {
        val explanation = PowerAssert.explanation
        val message = if (explanation == null) null else {
            val conditionArg = explanation.arguments.last()!!
            val source = explanation.source.substring(conditionArg.startOffset, conditionArg.endOffset)
            "Condition failed: $source"
        }
        fail(message, explanation)
    }
}

В этом примере функция check() собирает ошибки для последующего вывода, а функция require() немедленно завершает выполнение с ошибкой. Обе функции используют CallExplanation, чтобы извлечь исходный код условия, не прошедшего проверку, и включить его в сообщение об ошибке.

Полный пример см. в проекте fluent-assert.

Что дальше

Ознакомьтесь с нашими примерами проектов:

  • Простой проект с подключённым плагином

  • Более сложный проект с несколькими наборами исходного кода

  • Подборка примеров для экспериментов с возможностями библиотеки времени выполнения

20 августа 2026 г.
Плагин компилятора no-argПлагин компилятора SAM-with-receiver

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

Spec-Zone.ru

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