Fungsi buatan pengguna (UDF) Scala dan Java di Unity Catalog

Halaman ini menjelaskan cara membuat Scala dan Java fungsi yang ditentukan pengguna (UDF), mendaftarkannya di Unity Catalog, dan membagikannya di seluruh lingkungan komputasi. Unity Catalog UDF memungkinkan Anda menggunakan kembali logika JVM yang ada dengan tata kelola Dan kontrol akses Katalog Unity.

Tidak seperti UDF Scala yang dicakup dalam satu sesi yang terbatas pada satu notebook atau kluster, UDF yang terdaftar di Unity Catalog adalah:

  • Diatur: Dikelola dengan izin Unity Catalog dan kontrol akses.
  • Dapat digunakan kembali: Dibagikan di seluruh tim, notebook, pekerjaan, dan gudang SQL.
  • Dapat ditemukan: Terlihat di Catalog Explorer dan tabel sistem.
  • Terisolasi: Jalankan di kotak pasir dengan biaya cold-start satu kali per sesi. Pemanggilan berikutnya akan cepat.

Persyaratan

Ruang kerja Anda harus diaktifkan agar dapat menggunakan Katalog Unity. Persyaratan tambahan berikut berlaku.

Komputasi: Semua jenis komputasi didukung, termasuk notebook dan pekerjaan tanpa server, gudang SQL, dan Spark Declarative Pipelines di Lakeflow. Komputasi klasik memerlukan Databricks Runtime 18.2 atau lebih tinggi. Pada komputasi tanpa server dan gudang SQL, definisi UDF harus menentukan Lingkungan Versi 4 atau lebih tinggi di environment_version bidang . Persyaratan ini berlaku untuk definisi UDF, bukan untuk buku catatan panggilan atau pekerjaan. Lihat versi lingkungan Tanpa Server.

Pengembangan:

  • Scala: 2.13.16. Scala 2.12 tidak didukung.
  • JDK: 17.
  • Kemasan: JAR lemak yang berisi semua dependensi pihak ketiga yang digunakan oleh UDF.

Izin:

  • Buat UDF: USAGE dan CREATE FUNCTION pada skema, dan USAGE pada katalog.
  • Jalankan UDF: EXECUTE pada fungsi, dan USAGE pada skema dan katalog.
  • Akses file JAR: READ VOLUME pada volume tempat JAR disimpan.

Lihat Mengelola hak istimewa di Katalog Unity untuk informasi selengkapnya tentang izin Katalog Unity.

Membangun JAR UDF Anda

Kemas kode yang dikompilasi sebagai JAR dan unggah ke volume Katalog Unity sebelum mendaftarkan UDF. Pilih metode build:

Bangun secara lokal

Ikuti langkah-langkah berikut untuk membuat fat JAR menggunakan lingkungan pengembangan lokal.

Atur lingkungan Anda

Instal alat yang diperlukan di komputer lokal Anda. Perintah berikut adalah untuk macOS. Untuk platform lain, instal JDK 17 dan sbt (Scala) atau Maven (Java) menggunakan manajer paket platform Anda.

Scala

Instal JDK 17 dan sbt:

brew install openjdk@17
brew install sbt

Verifikasi penginstalan Anda:

java -version   # Should show Java 17
sbt --version   # Should show sbt version

Java

Instal JDK 17 dan Maven:

brew install openjdk@17
brew install maven

Verifikasi penginstalan Anda:

java -version   # Should show Java 17
mvn --version   # Should show Maven version

Membuat proyek Anda

Siapkan proyek di Scala atau Java.

Scala

Buat proyek Scala baru menggunakan sbt:

sbt new scala/scala-seed.g8

Saat diminta, masukkan nama proyek (misalnya, my-udf-project).

Konfigurasikan build.sbt

Ganti konten file Anda build.sbt dengan konfigurasi berikut:

scalaVersion := "2.13.16"

ThisBuild / organization := "com.example"

lazy val myUDF = (project in file("."))
  .settings(
    name := "my-udf"
  )

Aktifkan plugin sbt-assembly

Buat atau edit project/assembly.sbt dan tambahkan:

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.0.0")

Plugin ini membuat berkas JAR lengkap yang berisi semua dependensi Anda.

Java

Buat proyek Maven baru menggunakan arketipe mulai cepat:

mvn archetype:generate \
  -DgroupId=com.example \
  -DartifactId=my-udf \
  -DarchetypeArtifactId=maven-archetype-quickstart \
  -DinteractiveMode=false

Perintah ini membuat struktur proyek Maven standar dengan src/main/java direktori dan src/test/java .

Konfigurasikan pom.xml

Dalam file pom.xml yang dihasilkan, di dalam tag <project></project>, tambahkan blok <properties> dengan konfigurasi berikut:

<properties>
  <maven.compiler.source>17</maven.compiler.source>
  <maven.compiler.target>17</maven.compiler.target>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

Juga di dalam tag <project></project>, tambahkan blok <build> dengan konfigurasi berikut:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.5.0</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

maven-shade-plugin membuat fat JAR yang berisi seluruh dependensi Anda.

Tulis UDF Anda

Saat menulis UDF Anda, lihat Tipe data untuk tipe data yang didukung dan Pemetaan bahasa untuk melihat bagaimana tipe Scala dan Java dipetakan ke tipe SQL.

Handler UDF Anda harus memenuhi persyaratan berikut:

  • Scala: Tentukan handler sebagai metode pada object (bukan class). Nilai HANDLER merujuk ke sebuah metode pada object Scala.
  • Java: Tentukan handler sebagai public static metode.
  • Tanda tangan: Jenis parameter metode, urutan, dan jenis pengembalian harus sesuai dengan daftar argumen dan RETURNS ketik pernyataan Anda CREATE FUNCTION .
  • Skalar saja: Handler harus mengembalikan nilai skalar tunggal. Jenis pengembalian tabel tidak didukung.
  • Mandiri: Handler harus beroperasi hanya pada argumen inputnya. Ini tidak dapat menggunakan API Spark atau bergantung pada paket inti Spark. Lihat Batasan.

Note

Untuk Scala, handler dengan jenis parameter primitif (seperti Int) dilewati dan dikembalikan NULL ketika argumen input apa pun adalah SQL NULL. Untuk menerima dan menangani nilai NULL, bungkus parameter dengan Option, misalnya Option[Int].

Scala

Buat objek Scala di src/main/scala/com/example/MyUDF.scala dan tentukan fungsi UDF Anda.

Contoh dasar

package com.example

object MyUDF {
  def addOne(x: Int): Int = x + 1
}

Contoh dengan dependensi eksternal

Untuk menggunakan pustaka eksternal, tambahkan pustaka tersebut ke file build.sbt Anda:

scalaVersion := "2.13.16"

ThisBuild / organization := "com.example"

lazy val myUDF = (project in file("."))
  .settings(
    name := "currency-udf",
    libraryDependencies ++= Seq(
      "org.apache.commons" % "commons-lang3" % "3.12.0"
    )
  )

Kemudian gunakan dependensi di UDF Anda:

package com.example

import org.apache.commons.lang3.StringUtils

object CurrencyUDF {
  private val rates: Map[String, Double] = Map(
    "USD" -> 1.0,
    "EUR" -> 1.1,
    "GBP" -> 1.3,
    "JPY" -> 0.007
  )

  def convertToUSD(price: Double, currency: String): Double = {
    require(currency != null, "Currency must not be null")

    val normalizedCurrency = StringUtils.upperCase(currency)

    rates.get(normalizedCurrency) match {
      case Some(rate) => price * rate
      case None => throw new IllegalArgumentException(s"Unsupported currency: $currency")
    }
  }
}

Uji UDF Anda dengan uji unit sebelum menerapkannya. Lihat Menguji UDF secara lokal.

Java

Buat kelas Java di src/main/java/com/example/MyUDF.java dan tentukan UDF Anda sebagai metode statis publik.

Contoh dasar

package com.example;

public class MyUDF {
    public static int addOne(int x) {
        return x + 1;
    }
}

Contoh dengan dependensi eksternal

Untuk menggunakan pustaka eksternal, tambahkan pustaka tersebut ke bagian <dependencies> dari file pom.xml Anda:

<dependencies>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.12.0</version>
    </dependency>
</dependencies>

Kemudian gunakan dependensi di UDF Anda:

package com.example;

import org.apache.commons.lang3.StringUtils;
import java.util.Map;
import java.util.HashMap;

public class CurrencyUDF {
    private static final Map<String, Double> rates = new HashMap<>();

    static {
        rates.put("USD", 1.0);
        rates.put("EUR", 1.1);
        rates.put("GBP", 1.3);
        rates.put("JPY", 0.007);
    }

    public static double convertToUSD(double price, String currency) {
        if (currency == null) {
            throw new IllegalArgumentException("Currency must not be null");
        }

        String normalizedCurrency = StringUtils.upperCase(currency);

        if (!rates.containsKey(normalizedCurrency)) {
            throw new IllegalArgumentException("Unsupported currency: " + currency);
        }

        return price * rates.get(normalizedCurrency);
    }
}

Uji UDF Anda dengan uji unit sebelum menerapkannya. Lihat Menguji UDF secara lokal.

Note

UDF Anda berjalan di kotak pasir terisolasi tanpa sesi Spark aktif, sehingga tidak dapat menggunakan API Spark dari dalam isi fungsi. Misalnya, Anda tidak dapat membuat atau mengoperasikan dataFrame atau Himpunan Data, menjalankan spark.sql(...), atau mengakses SparkSession atau SparkContext. UDF harus berupa logika mandiri atas argumen inputnya. Ini juga tidak dapat bergantung pada paket inti Spark.

Buat fat JAR Anda

Bangun proyek Anda untuk membuat fat JAR yang berisi semua dependensi.

Scala

Dari direktori akar proyek Anda, jalankan:

sbt clean assembly

fat JAR dibuat di target/scala-2.13/ dengan nama seperti my-udf-assembly-0.1.0-SNAPSHOT.jar.

Java

Dari direktori akar proyek Anda, jalankan:

mvn clean package

Fat JAR dibuat di target/ dengan nama seperti my-udf-1.0-SNAPSHOT.jar.

Unggah JAR Anda ke volume Unity Catalog

Jika Anda belum memiliki volume Unity Catalog, buatlah volume tersebut:

CREATE VOLUME IF NOT EXISTS my_catalog.my_schema.udf_jars
COMMENT 'Storage for UDF JAR files';

Jika pengguna lain perlu menjalankan UDF, berikan READ VOLUME pada volume:

GRANT READ VOLUME ON VOLUME my_catalog.my_schema.udf_jars TO `user@example.com`;

Unggah file JAR Anda ke volume menggunakan Catalog Explorer:

  1. Di ruang kerja Azure Databricks Anda, klik Ikon data.Katalog untuk membuka Catalog Explorer.
  2. Pilih katalog, lalu pilih skema yang berisi volume Anda.
  3. Klik nama volume.
  4. Klik Unggah ke volume ini dan pilih file JAR Anda.
  5. Klik Unggah.
  6. Setelah pengunggahan selesai, klik nama file JAR Anda.
  7. Klik Salin jalur untuk menyalin jalur volume ke clipboard Anda. Misalnya, /Volumes/my_catalog/my_schema/udf_jars/my-udf-assembly-0.1.0-SNAPSHOT.jar (Scala) atau /Volumes/my_catalog/my_schema/udf_jars/my-udf-1.0-SNAPSHOT.jar (Java). Anda memerlukan jalur ini saat mendaftarkan UDF.

Menyusun di buku catatan

Anda dapat mengkompilasi UDF, mengemasnya sebagai JAR, dan mengunggahnya ke volume Katalog Unity langsung dari buku catatan Azure Databricks. Pendekatan ini cocok untuk UDF kecil yang tidak memiliki dependensi. Untuk UDF dengan pustaka pihak ketiga, gunakan Bangun secara lokal.

Sel Python berikut menulis Java UDF yang membersihkan string (memangkas spasi kosong, menciutkan spasi berulang, dan huruf kecil), mengkompilasinya dengan JDK 17, mengemasnya sebagai JAR, dan menyalinnya ke volume Katalog Unity. Perbarui volume_path agar mengarah ke volume yang sudah ada dan yang Anda miliki izin WRITE VOLUME untuk mengaksesnya.

import os
import subprocess
import shutil

build_dir = "/tmp/udf_build"
package_dir = f"{build_dir}/src/com/databricks/udf"
classes_dir = f"{build_dir}/classes"
os.makedirs(package_dir, exist_ok=True)
os.makedirs(classes_dir, exist_ok=True)

# The UDF handler: a public static method on a plain Java class.
# The doubled backslashes produce a single backslash in the Java source (\\s+).
udf_code = """package com.databricks.udf;
public class StringCleanUDF {
    public static String clean(String input) {
        if (input == null) return null;
        return input.trim().replaceAll("\\\\s+", " ").toLowerCase();
    }
}
"""
with open(f"{package_dir}/StringCleanUDF.java", "w") as f:
    f.write(udf_code)

# Compile with JDK 17 to match Environment Version 4.
subprocess.run(
    ["javac", "--release", "17", "-d", classes_dir, f"{package_dir}/StringCleanUDF.java"],
    check=True,
)

# Package the compiled class into a JAR.
jar_path = f"{build_dir}/string_clean_udf.jar"
subprocess.run(["jar", "cf", jar_path, "-C", classes_dir, "."], check=True)

# Copy the JAR to a Unity Catalog volume.
volume_path = "/Volumes/my_catalog/my_schema/udf_jars/string_clean_udf.jar"
os.makedirs(os.path.dirname(volume_path), exist_ok=True)
shutil.copy2(jar_path, volume_path)

print(f"JAR uploaded to: {volume_path}")

Setelah JAR berada dalam volume, daftarkan UDF. Gunakan LANGUAGE JAVA dan atur HANDLER ke metode yang sepenuhnya memenuhi syarat, seperti com.databricks.udf.StringCleanUDF.clean.

Daftarkan UDF Anda di Unity Catalog

Setelah Anda membuat dan mengunggah JAR, gunakan CREATE FUNCTION pernyataan untuk mendaftarkan UDF Anda di Katalog Unity.

Scala

CREATE OR REPLACE FUNCTION my_catalog.my_schema.add_one(x INT)
RETURNS INT
LANGUAGE SCALA
DETERMINISTIC
ENVIRONMENT (
  java_dependencies = '["/Volumes/my_catalog/my_schema/udf_jars/my-udf-assembly-0.1.0-SNAPSHOT.jar"]',
  environment_version = '4'
)
HANDLER 'com.example.MyUDF.addOne';

Java

CREATE OR REPLACE FUNCTION my_catalog.my_schema.add_one(x INT)
RETURNS INT
LANGUAGE JAVA
DETERMINISTIC
ENVIRONMENT (
  java_dependencies = '["/Volumes/my_catalog/my_schema/udf_jars/my-udf-1.0-SNAPSHOT.jar"]',
  environment_version = '4'
)
HANDLER 'com.example.MyUDF.addOne';

Pernyataan CREATE FUNCTION menggunakan parameter berikut:

  • LANGUAGE: Bahasa UDF.

  • HANDLER: Jalur yang sepenuhnya memenuhi syarat ke metode , dalam format 'package.Object.method' (Scala) atau 'package.ClassName.method' (Java).

  • DETERMINISTIC: Menyatakan bahwa fungsi selalu mengembalikan output yang sama untuk input yang sama, memungkinkan pengoptimalan kueri.

    Note

    Hapus DETERMINISTIC jika fungsi Anda memanggil API eksternal atau memiliki perilaku non-deterministik lainnya.

  • ENVIRONMENT: Menentukan lingkungan eksekusi untuk UDF.

    • java_dependencies: Larik JSON yang berisi jalur file JAR di volume Unity Catalog Anda. Ini adalah jalur file yang Anda salin di langkah sebelumnya. Gunakan tanda kutip tunggal di sekitar array dan tanda kutip ganda di sekitar jalur.
    • environment_version: Harus '4' atau lebih tinggi untuk UDF Scala dan Java. Environment Version 4 menentukan Scala 2.13.16 dan JDK 17. Lihat versi lingkungan Tanpa Server.

Panggil UDF Anda di SQL dan buku catatan

Setelah pendaftaran, Anda dapat memanggil UDF dalam kueri, buku catatan, dan tampilan SQL:

-- Simple select
SELECT my_catalog.my_schema.add_one(5) AS result;

-- With table data
SELECT
  id,
  price,
  currency,
  my_catalog.my_schema.convert_to_usd(price, currency) AS price_usd
FROM my_catalog.my_schema.transactions;

-- Filtering
SELECT *
FROM my_catalog.my_schema.products
WHERE my_catalog.my_schema.convert_to_usd(price, currency) > 100;

-- Aggregation
SELECT
  category,
  SUM(my_catalog.my_schema.convert_to_usd(price, currency)) AS total_usd
FROM my_catalog.my_schema.sales
GROUP BY category;

Tata kelola dan berbagi

Gunakan izin Unity Catalog untuk mengontrol siapa yang dapat menjalankan UDF Anda dan membuatnya dapat ditemukan di seluruh organisasi Anda.

Memberikan izin

Gunakan Catalog Explorer atau SQL untuk memberikan izin yang diperlukan bagi pengguna lain untuk menjalankan UDF Anda.

Eksplorer Katalog

  1. Di bar samping, klik ikon Data.Katalog.
  2. Pilih katalog, lalu pilih skema yang berisi fungsi Anda.
  3. Klik nama fungsi.
  4. Di tab Izin , klik Berikan.
  5. Pilih prinsipal yang ingin Anda berikan akses, lalu pilih izin EXECUTE.
  6. Klik tombol Konfirmasi.

SQL

Jalankan perintah berikut ini di notebook atau editor Databricks SQL untuk memberikan EXECUTE izin kepada pengguna atau grup.

-- Grant to a specific user
GRANT EXECUTE ON FUNCTION my_catalog.my_schema.add_one TO `user@example.com`;

-- Grant to a group
GRANT EXECUTE ON FUNCTION my_catalog.my_schema.add_one TO `data-engineers`;

Mencabut izin

Gunakan Catalog Explorer atau SQL untuk mencabut izin dari pengguna lain.

Eksplorer Katalog

  1. Di bar samping, klik ikon Data.Katalog.
  2. Pilih katalog, lalu pilih skema yang berisi fungsi Anda.
  3. Klik nama fungsi.
  4. Di tab Izin , pilih kotak centang di samping prinsipal yang ingin Anda cabut aksesnya. Klik Batalkan.
  5. Di pemberitahuan, klik Cabut.

SQL

Jalankan perintah berikut ini di notebook atau editor Databricks SQL untuk mencabut EXECUTE izin dari pengguna atau grup.

-- Revoke from specific user
REVOKE EXECUTE ON FUNCTION my_catalog.my_schema.add_one FROM `user@example.com`;

-- Revoke from a group
REVOKE EXECUTE ON FUNCTION my_catalog.my_schema.add_one FROM `data-engineers`;

Jelajahi UDF

Untuk menemukan UDF yang dikelola di Unity Catalog, kuerilah tabel information_schema.routines, dengan mengganti nilai my_catalog dan my_schema:

SELECT
  routine_catalog,
  routine_schema,
  routine_name,
  routine_definition,
  created
FROM system.information_schema.routines
WHERE routine_catalog = 'my_catalog'
  AND routine_schema = 'my_schema';

Memperbarui UDF Anda

Untuk memperbarui Unity Catalog UDF yang ada dengan kode baru:

  1. Buat perubahan pada kode Anda secara lokal.
  2. Bangun ulang JAR dengan nomor versi baru.
    • Scala: sbt clean assembly (misalnya, my-udf-assembly-0.2.0-SNAPSHOT.jar)
    • Java: mvn clean package (misalnya, my-udf-2.0-SNAPSHOT.jar)
  3. Unggah JAR baru ke volume Katalog Unity.
  4. Gunakan CREATE OR REPLACE FUNCTION dengan nama fungsi yang sama untuk memperbarui UDF. Pastikan bahwa Anda merujuk ke JAR terbaru di java_dependencies.

Azure Databricks menggunakan kode baru pada pemanggilan berikutnya. Anda tidak perlu menghidupkan ulang kluster Anda.

Pengoptimalan performa

Latensi mulai dingin

Panggilan UDF pertama dalam sesi menginisialisasi kotak pasir terisolasi, yang menambahkan latensi. Panggilan berikutnya dalam sesi yang sama lebih cepat. Perhitungkan hal ini saat membuat tolok ukur atau merancang beban kerja yang sensitif terhadap latensi.

Penyimpanan dalam tembolok untuk komputasi yang mahal

Jika UDF Anda melakukan inisialisasi atau komputasi yang mahal, cache hasilnya untuk menghitungnya hanya sekali.

Scala

val Gunakan bidang di objek Scala untuk menyimpan hasilnya:

package example

object CachedUDF {
  // Computed once and cached
  val expensiveData: Map[String, Double] = {
    // Load data from somewhere expensive
    Map("key1" -> 1.0, "key2" -> 2.0)
  }

  def lookup(key: String): Double = {
    expensiveData.getOrElse(key, 0.0)
  }
}

Java

static Gunakan bidang dengan blok penginisialisasi statis untuk menyimpan hasilnya:

package example;

import java.util.Map;
import java.util.HashMap;

public class CachedUDF {
    // Computed once and cached
    private static Map<String, Double> expensiveData;

    static {
        // Load data from somewhere expensive
        expensiveData = new HashMap<>();
        expensiveData.put("key1", 1.0);
        expensiveData.put("key2", 2.0);
    }

    public static double lookup(String key) {
        return expensiveData.getOrDefault(key, 0.0);
    }
}

Gunakan DETERMINISTIK jika sesuai

Tandai UDF Anda sebagai DETERMINISTIC jika selalu menghasilkan keluaran yang sama untuk masukan yang sama. Ini memungkinkan pengoptimal kueri untuk menyimpan hasil dan meningkatkan performa.

Keterbatasan

  • Hanya UDF skalar yang didukung. Fungsi agregat yang ditentukan pengguna (UDAF) dan fungsi tabel yang ditentukan pengguna (UDTF) tidak didukung.
  • UDF berjalan di kotak pasir terisolasi tanpa sesi Spark aktif. API Spark (SparkSession, SparkContext, spark.sql(...), DataFrame dan operasi Himpunan Data) tidak tersedia.
  • UDF tidak dapat bergantung pada paket inti Spark.
  • UDF tidak memiliki akses ke file workspace atau volume Unity Catalog saat dijalankan.

Praktik terbaik

Databricks merekomendasikan praktik berikut:

  • Versi file JAR Anda. Misalnya, my-udf-0.1.0.jar, my-udf-0.2.0.jar.
  • Validasi pemetaan jenis SQL sebelum penyebaran. Lihat Pemetaan bahasa.
  • Berikan READ VOLUME dan EXECUTE izin hanya kepada pengguna yang perlu menjalankan UDF. Gunakan kepemilikan grup untuk UDF yang dibagikan antar tim.

Menguji UDF secara lokal

Uji UDF Anda dengan uji unit sebelum menerapkannya ke lingkungan produksi.

Scala

Untuk menguji src/main/scala/example/MyUDF.scala, buat file pengujian di src/test/scala/example/MyUDFTest.scala:

package example

import org.scalatest.funsuite.AnyFunSuite

class MyUDFTest extends AnyFunSuite {
  test("addOne should add 1 to input") {
    assert(MyUDF.addOne(5) == 6)
  }

  test("addOne should handle negative numbers") {
    assert(MyUDF.addOne(-1) == 0)
  }
}

Tambahkan dependensi pengujian ke build.sbt:

libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.15" % Test

Untuk menjalankan pengujian:

sbt test

Java

Untuk menguji src/main/java/com/example/MyUDF.java, buat file pengujian di src/test/java/com/example/MyUDFTest.java:

package com.example;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class MyUDFTest {
    @Test
    public void testAddOne() {
        assertEquals(6, MyUDF.addOne(5));
    }

    @Test
    public void testAddOneWithNegativeNumbers() {
        assertEquals(0, MyUDF.addOne(-1));
    }
}

Tambahkan dependensi JUnit ke bagian <dependencies> di pom.xml Anda:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>

Untuk menjalankan pengujian:

mvn test

Sumber daya tambahan