Power-assert 編譯器外掛程式
Kotlin Power-assert 編譯器外掛程式透過提供包含上下文資訊的詳細失敗訊息,來改善偵錯體驗。它透過在失敗訊息中自動產生中間值,簡化了撰寫測試的過程。它能協助您了解測試失敗的原因,而無需複雜的斷言程式庫。
這是該外掛程式提供的一個範例訊息:
Incorrect length
assert(hello.length == world.substring(1, 4).length) { "Incorrect length" }
| | | | | |
| | | | | 3
| | | | orl
| | | world!
| | false
| 5
HelloPower-assert 外掛程式的主要特性:
- 增強的錯誤訊息:該外掛程式會擷取並顯示斷言中的變數和子運算式的值,以清楚識別失敗原因。
- 簡化測試:自動產生具備豐富資訊的失敗訊息,減少對複雜斷言程式庫的需求。
- 支援多個函式:預設情況下,它會轉換
assert()函式呼叫,但也可以轉換其他函式,例如require()、check()和assertTrue()。
套用外掛程式
Gradle
若要啟用 Power-assert 外掛程式,請按照以下方式設定您的 build.gradle(.kts) 檔案:
// build.gradle.kts
plugins {
kotlin("multiplatform") version "2.3.0"
kotlin("plugin.power-assert") version "2.3.0"
}// build.gradle
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '2.3.0'
id 'org.jetbrains.kotlin.plugin.power-assert' version '2.3.0'
}Power-assert 外掛程式提供了多個選項來套用其行為:
functions:完整限定的函式路徑列表。Power-assert 外掛程式將轉換對這些函式的呼叫。如果未指定,預設僅轉換kotlin.assert()呼叫。includedSourceSets:Power-assert 外掛程式將轉換的 Gradle 原始碼集列表。如果未指定,預設將轉換所有 測試原始碼集 (test source sets)。
若要自訂行為,請將 powerAssert {} 區塊加入您的建置指令碼檔案:
// build.gradle.kts
powerAssert {
functions = listOf("kotlin.assert", "kotlin.test.assertTrue", "kotlin.test.assertEquals", "kotlin.test.assertNull")
includedSourceSets = listOf("commonMain", "jvmMain", "jsMain", "nativeMain")
}// build.gradle
powerAssert {
functions = ["kotlin.assert", "kotlin.test.assertTrue", "kotlin.test.assertEquals", "kotlin.test.assertNull"]
includedSourceSets = ["commonMain", "jvmMain", "jsMain", "nativeMain"]
}由於該外掛程式處於實驗性 (Experimental) 階段,您每次組建應用程式時都會看到警告。若要排除這些警告,請在宣告 powerAssert {} 區塊之前加入此 @OptIn 註解:
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
@OptIn(ExperimentalKotlinGradlePluginApi::class)
powerAssert {
...
}Maven
若要在 Maven 專案中啟用 Power-assert 編譯器外掛程式,請更新 pom.xml 檔案中 kotlin-maven-plugin 的 <plugin> 區段:
<build>
<plugins>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>2.3.0</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>
<!-- 指定 Power-assert 外掛程式 -->
<compilerPlugins>
<plugin>power-assert</plugin>
</compilerPlugins>
</configuration>
<!-- 加入 Power-assert 外掛程式相依性 -->
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-power-assert</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>您可以使用 function 選項來自訂 Power-assert 外掛程式轉換哪些函式。例如,您可以包含 kotlin.test.assertTrue()、kotlin.test.assertEquals() 等。如果未指定,預設僅轉換 kotlin.assert() 呼叫。
在 kotlin-maven-plugin 的 <configuration> 區段中指定此選項:
<configuration>
<!-- 指定要轉換的函式 -->
<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("jvm") version "2.3.0"
kotlin("plugin.power-assert") version "2.3.0"
}
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.jvm' version '2.3.0'
id 'org.jetbrains.kotlin.plugin.power-assert' version '2.3.0'
}
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.3.0</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.3.0</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.3.0</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.3.0</version>
</dependency>
</dependencies>
</project>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" }
}
}如果您在啟用 Power-assert 外掛程式的情況下執行 testFunction() 測試,您將獲得明確的失敗訊息:
Incorrect length
assert(hello.length == world.substring(1, 4).length) { "Incorrect length" }
| | | | | |
| | | | | 3
| | | | orl
| | | world!
| | false
| 5
Hello若要獲得更完整的錯誤訊息,請始終將變數內嵌 (inline) 到測試函式參數中。考慮以下測試函式:
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)
}
}執行程式碼的輸出並未提供足夠的資訊來找出問題原因:
Assertion failed
assert(isValidName && isValidAge)
| |
| false
true將變數內嵌到 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)
}
}執行後,您會獲得關於出錯原因的更明確資訊:
Assertion failed
assert(person.name.startsWith("A") && person.name.length > 3 && person.age > 20 && person.age < 29)
| | | | | | | | | |
| | | | | | | | | false
| | | | | | | | 10
| | | | | | | Person(name=Alice, age=10)
| | | | | | true
| | | | | 5
| | | | Alice
| | | Person(name=Alice, age=10)
| | true
| Alice
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該訊息顯示了導致失敗的中間值,使偵錯變得更容易。
軟斷言 (Soft assertions)
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("
"))
}
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()函式的套件完整名稱。
之後,您就可以在測試程式碼中使用它:
// 匯入 assertSoftly() 函式
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}" }
| | |
| | false
| 40000
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}" }
| | |
| | false
| 150
Employee(name=Dave, age=150, salary=70000)