Scala a Java uživatelem definované funkce (UDF) v katalogu Unity

Tato stránka popisuje, jak vytvořit Scala a Java uživatelem definované funkce (UDF), zaregistrovat je v katalogu Unity a sdílet je napříč výpočetními prostředími. Uživatelsky definované funkce (UDF) služby Unity Catalog vám umožňují opakovaně používat existující logiku JVM při zachování správy a řízení přístupu ve službě Unity Catalog.

Na rozdíl od funkcí Scala UDF s rozsahem relace, které jsou omezeny na jeden poznámkový blok nebo cluster, jsou registrované funkce UDF v katalogu Unity:

  • Řízení: Spravováno pomocí oprávnění katalogu Unity a řízení přístupu.
  • Opakovaně použitelné: Sdíleno napříč týmy, poznámkovými bloky, úlohami a sklady SQL.
  • Zjistitelné: Viditelné v Průzkumníku katalogu a systémových tabulkách
  • Izolované: Spouští se v sandboxech s jednorázovými náklady na studený start pro každou relaci. Následná volání jsou rychlá.

Požadavky

Pro katalog Unity musí být povolený váš pracovní prostor. Platí následující další požadavky.

Výpočty: Podporují se všechny typy výpočetních prostředků, včetně bezserverových poznámkových bloků a úloh, skladů SQL a deklarativních kanálů Sparku v lakeflow. Klasické výpočetní prostředí vyžaduje Databricks Runtime 18.2 nebo novější. V bezserverových výpočetních prostředích a datových skladech SQL musí definice UDF v poli environment_version uvádět verzi prostředí 4 nebo vyšší. Tento požadavek se vztahuje na definici UDF, nikoli na notebook, který ji volá, ani na úlohu. Viz verze bezserverového prostředí .

Vývoj:

  • Scala: 2.13.16. Scala 2.12 se nepodporuje.
  • JDK: 17.
  • Balení: Kompletní JAR obsahující všechny závislosti třetích stran používané uživatelsky definovanou funkcí (UDF).

Oprávnění:

  • Vytvořte UDF: USAGE a CREATE FUNCTION ve schématu a USAGE v katalogu.
  • Spusťte UDF: EXECUTE u funkce a USAGE u schématu a katalogu.
  • Přístup k souboru JAR: READ VOLUME na svazku, ve kterém je soubor JAR uložený.

Další informace o oprávněních katalogu Unity najdete v tématu Správa oprávnění v katalogu Unity .

Vytvořte si UDF JAR

Zabalte zkompilovaný kód jako soubor JAR a před registrací UDF ho nahrajte do svazku v Unity Catalog. Zvolte metodu sestavení:

Sestavení v místním prostředí

Pomocí těchto kroků sestavte fat JAR pomocí místního vývojového prostředí.

Nastavení prostředí

Nainstalujte požadované nástroje na místní počítač. Následující příkazy jsou určené pro macOS. Pro jiné platformy nainstalujte sadu JDK 17 a sbt (Scala) nebo Maven (Java) pomocí správce balíčků vaší platformy.

Scala

Nainstalujte sadu JDK 17 a sbt:

brew install openjdk@17
brew install sbt

Ověřte instalaci:

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

Java

Nainstalujte JDK 17 a Maven:

brew install openjdk@17
brew install maven

Ověřte instalaci:

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

Vytvoření projektu

Nastavte projekt v jazyce Scala nebo Java.

Scala

Vytvořte nový projekt Scala pomocí sbt:

sbt new scala/scala-seed.g8

Po zobrazení výzvy zadejte název projektu (například my-udf-project).

Nakonfigurujte build.sbt

Nahraďte obsah souboru build.sbt následující konfigurací:

scalaVersion := "2.13.16"

ThisBuild / organization := "com.example"

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

Povolení modulu plug-in sbt-assembly

Vytvořte nebo upravte project/assembly.sbt a přidejte:

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

Tento plugin vytvoří fat JAR soubor, který obsahuje všechny vaše závislosti.

Java

Vytvořte nový projekt Maven pomocí archetypu rychlého startu:

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

Tento příkaz vytvoří standardní strukturu projektu Maven s src/main/java adresáři a src/test/java adresáři.

Nakonfigurujte pom.xml

Do vygenerovaného pom.xml souboru v rámci <project></project> značek přidejte <properties> blok s následující konfigurací:

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

Také uvnitř značek <project></project> přidejte blok <build> s následující konfigurací:

<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 vytvoří kompletní JAR obsahující všechny potřebné závislosti.

Napište svou UDF

Při psaní UDF se podívejte na datové typypodporovaných datových typů a mapování jazyka a zjistěte, jak se typy Scala a Java mapují na typy SQL.

Obslužná rutina UDF musí splňovat následující požadavky:

  • Scala: Definujte obslužnou rutinu jako metodu object (nikoli class). Hodnota HANDLER odpovídá metodě na Scala object.
  • Java: Definujte obslužnou rutinu jako metodupublic static.
  • Podpis: Typy parametrů, pořadí a návratový typ metody musí odpovídat seznamu argumentů a RETURNS typu v CREATE FUNCTION příkazu.
  • Pouze skalární: Obslužná rutina musí vrátit jednu skalární hodnotu. Návratové typy tabulek nejsou podporovány.
  • Samostatná rutina: Obslužná rutina musí pracovat pouze s jeho vstupními argumenty. Nemůže používat rozhraní Spark API nebo závisí na základních balíčcích Sparku. Viz Omezení.

Note

Pro Scala se obslužná rutina s primitivním typem parametru (například Int) přeskočí a vrátí NULL , pokud je libovolný vstupní argument SQL NULL. Chcete-li přijímat a zpracovávat NULL hodnoty, zabalte parametr do Optionsouboru , například Option[Int].

Scala

Vytvořte objekt src/main/scala/com/example/MyUDF.scala Scala a definujte funkci UDF.

Základní příklad

package com.example

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

Příklad s externí závislostí

Pokud chcete použít externí knihovny, přidejte je do build.sbt souboru:

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"
    )
  )

Poté použijte tuto závislost v UDF:

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")
    }
  }
}

Před nasazením otestujte UDF pomocí jednotkových testů. Viz Lokální testování UDF.

Java

Vytvořte třídu jazyka Java v src/main/java/com/example/MyUDF.java a definujte svou funkci UDF jako veřejnou statickou metodu.

Základní příklad

package com.example;

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

Příklad s externí závislostí

Pokud chcete použít externí knihovny, přidejte je do <dependencies> části pom.xml souboru:

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

Pak použijte závislost v UDF:

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);
    }
}

Před nasazením otestujte UDF pomocí jednotkových testů. Viz Testování UDF v místním prostředí.

Note

Vaše UDF běží v izolovaném prostředí bez aktivní relace Spark, takže uvnitř těla funkce nemůže používat API Sparku. Nemůžete například vytvářet DataFramy ani Datasety, provádět operace nad DataFramy či Datasety, spustit spark.sql(...) ani přistupovat k SparkSession nebo SparkContext. Uživatelsky definovaná funkce musí obsahovat samostatnou logiku pracující pouze s jejími vstupními argumenty. Také nemůže záviset na základních balíčcích Sparku.

Sestavte svůj fat JAR

Vytvořte projekt tak, aby vytvořil fat JAR obsahující všechny závislosti.

Scala

V kořenovém adresáři projektu spusťte:

sbt clean assembly

Fat JAR se vytvoří v target/scala-2.13/ pod názvem například my-udf-assembly-0.1.0-SNAPSHOT.jar.

Java

V kořenovém adresáři projektu spusťte:

mvn clean package

Soubor fat JAR se vytvoří v target/ pod názvem jako my-udf-1.0-SNAPSHOT.jar.

Nahrajte soubor JAR do volumu Unity Catalog

Pokud ještě nemáte svazek katalogu Unity, vytvořte ho:

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

Pokud ostatní uživatelé potřebují spustit UDF, udělte jim READ VOLUME pro daný svazek:

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

Nahrajte soubor JAR do svazku pomocí Průzkumníka katalogu:

  1. V pracovním prostoru Azure Databricks klikněte na ikonu Data. Klikněte na Katalog pro otevření Průzkumníka katalogu.
  2. Vyberte katalog a pak vyberte schéma, které obsahuje váš svazek.
  3. Klikněte na název svazku.
  4. Klikněte na Nahrát do tohoto svazku a vyberte soubor JAR.
  5. Klikněte na tlačítko Odeslat.
  6. Po dokončení nahrávání klikněte na název souboru JAR.
  7. Kliknutím na Kopírovat cestu zkopírujte cestu ke svazku do schránky. Například /Volumes/my_catalog/my_schema/udf_jars/my-udf-assembly-0.1.0-SNAPSHOT.jar (Scala) nebo /Volumes/my_catalog/my_schema/udf_jars/my-udf-1.0-SNAPSHOT.jar (Java). Tuto cestu potřebujete při registraci UDF.

Sestavení v poznámkovém bloku

UDF můžete zkompilovat, zabalit ho jako soubor JAR a nahrát ho do svazku katalogu Unity přímo z Azure Databricks poznámkového bloku. Tento přístup funguje u malých uživatelsky definovaných funkcí bez závislostí. Pro UDF s knihovnami třetích stran použijte možnost Sestavit místně.

Následující buňka Pythonu zapíše funkci Java UDF, která vyčistí řetězec (ořízne bílé znaky, sloučí opakované mezery a převede text na malá písmena), zkompiluje ji pomocí JDK 17, zabalí ji do souboru JAR a zkopíruje ji do svazku v Unity Catalog. Aktualizujte volume_path tak, aby odkazoval na existující svazek, ke kterému máte WRITE VOLUME oprávnění.

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}")

Jakmile je soubor JAR ve svazku, zaregistrujte uživatelsky definovanou funkci. Použijte LANGUAGE JAVA a nastavte HANDLER na plně kvalifikovaný název metody, například com.databricks.udf.StringCleanUDF.clean.

Zaregistrujte svou UDF v katalogu Unity

Po sestavení a nahrání souboru JAR pomocí příkazu CREATE FUNCTION zaregistrujte UDF v katalogu 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';

Příkaz CREATE FUNCTION používá následující parametry:

  • LANGUAGE: Jazyk UDF.

  • HANDLER: Plně kvalifikovaná cesta k metodě ve formátu 'package.Object.method' (Scala) nebo 'package.ClassName.method' (Java).

  • DETERMINISTIC: Deklaruje, že funkce vždy vrací stejný výstup pro stejný vstup a povoluje optimalizaci dotazů.

    Note

    Odstraňte DETERMINISTIC, pokud vaše funkce volá externí rozhraní API nebo má jiné nedeterministické chování.

  • ENVIRONMENT: Definuje prostředí pro spuštění uživatelsky definované funkce (UDF).

    • java_dependencies: Pole JSON s cestami k souborům JAR ve svazcích katalogu Unity. Toto je cesta k souboru, kterou jste zkopírovali v předchozím kroku. Kolem pole používejte jednoduché uvozovky a dvojité uvozovky kolem cest.
    • environment_version: Pro UDF v jazycích Scala a Java musí být '4' nebo vyšší. Verze prostředí 4 specifikuje Scala 2.13.16 a JDK 17. Viz verze bezserverového prostředí .

Volání UDF v SQL a poznámkových blocích

Po registraci můžete volat UDF v dotazech SQL, poznámkových blocích a zobrazeních:

-- 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;

Zásady správného řízení a sdílení

Pomocí oprávnění Unity Catalog můžete řídit, kdo může vaši uživatelsky definovanou funkci (UDF) spouštět, a zajistit, aby ji bylo možné najít v rámci celé organizace.

Udělení oprávnění

Pomocí Průzkumníka katalogu nebo SQL udělte ostatním uživatelům potřebná oprávnění ke spouštění funkcí definovaných uživatelem.

Průzkumník katalogu

  1. Na bočním panelu klikněte na ikonu Data.Katalog.
  2. Vyberte katalog a pak vyberte schéma, které obsahuje vaši funkci.
  3. Klikněte na název funkce.
  4. Na kartě Oprávnění klikněte na Udělit.
  5. Vyberte objekty zabezpečení, kterým chcete udělit přístup, a vyberte oprávnění EXECUTE.
  6. Klikněte na tlačítko Potvrdit.

SQL

Spuštěním následujícího příkazu v poznámkovém bloku nebo editoru SQL Databricks udělte EXECUTE uživateli nebo skupině oprávnění.

-- 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`;

Odvolání oprávnění

K odvolání oprávnění od jiných uživatelů použijte Průzkumníka katalogu nebo SQL.

Průzkumník katalogu

  1. Na bočním panelu klikněte na ikonu Data.Katalog.
  2. Vyberte katalog a pak vyberte schéma, které obsahuje vaši funkci.
  3. Klikněte na název funkce.
  4. Na kartě Oprávnění zaškrtněte políčko vedle objektu zabezpečení, ze kterého chcete odvolat přístup. Klepněte na tlačítko Odvolat.
  5. V oznámení klepněte na tlačítko Odvolat.

SQL

Spuštěním následujícího příkazu v poznámkovém bloku nebo editoru SQL Databricks odvoláte EXECUTE oprávnění uživatele nebo skupiny.

-- 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`;

Objevte funkce UDF

Pokud chcete najít funkce UDF spravované v Unity Catalog, zadejte dotaz na tabulku information_schema.routines a nahraďte hodnoty my_catalog a 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';

Aktualizujte svůj UDF

Chcete-li aktualizovat existující uživatelsky definovanou funkci (UDF) v katalogu Unity novým kódem:

  1. Proveďte změny kódu místně.
  2. Znovu sestavte soubor JAR s novým číslem verze.
    • Scala: sbt clean assembly (například my-udf-assembly-0.2.0-SNAPSHOT.jar)
    • Java: mvn clean package (napříkladmy-udf-2.0-SNAPSHOT.jar)
  3. Nahrajte nový soubor JAR do svazku katalogu Unity.
  4. K aktualizaci funkce definované uživatelem (UDF) použijte CREATE OR REPLACE FUNCTION se stejným názvem funkce. Ověřte, že odkazujete na nejnovější soubor JAR v souboru java_dependencies.

Azure Databricks použije nový kód při dalším vyvolání. Cluster nemusíte restartovat.

Optimalizace výkonu

Latence studeného spuštění

První volání UDF během relace inicializuje izolovaný sandbox, což přidává latenci. Další volání ve stejné relaci jsou rychlejší. Počítejte s tím při provádění benchmarků nebo navrhování úloh citlivých na latenci.

Ukládání drahých výpočtů do mezipaměti

Pokud vaše funkce definovaná uživatelem provádí náročnou inicializaci nebo výpočet, uložte výsledek do mezipaměti, abyste jej vypočítali pouze jednou.

Scala

val K uložení výsledku do mezipaměti použijte pole v objektu Scala:

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 K uložení výsledku do mezipaměti použijte pole s blokem statického inicializátoru:

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);
    }
}

Pokud je to vhodné, použijte DETERMINISTIC

Označte své UDF jako DETERMINISTIC, pokud vždy vrací stejný výstup pro stejný vstup. To umožňuje optimalizátoru dotazů ukládat výsledky do mezipaměti a zlepšit výkon.

Omezení

  • Podporovány jsou pouze skalární funkce UDF. Uživatelem definované agregační funkce (UDAF) a uživatelem definované funkce tabulek (UDTF) se nepodporují.
  • UDF běží v izolovaném sandboxu bez aktivní relace Spark. Rozhraní API Spark (SparkSession, SparkContext, spark.sql(...), operace DataFrame a Dataset) nejsou k dispozici.
  • UDF nemohou záviset na balíčcích jádra Sparku.
  • Funkce definované uživatelem nemají přístup k souborům pracovního prostoru ani ke svazkům katalogu Unity za běhu.

Osvědčené postupy

Databricks doporučuje následující postupy:

  • Verze souborů JAR. Například , my-udf-0.1.0.jarmy-udf-0.2.0.jar.
  • Před nasazením ověřte mapování typů SQL. Viz mapování jazyka.
  • Udělte oprávnění READ VOLUME a EXECUTE pouze uživatelům, kteří potřebují spustit UDF. Pro UDF sdílené mezi týmy používejte skupinové vlastnictví.

Lokální testování UDF

Před nasazením do produkčního prostředí otestujte UDF pomocí testů jednotek.

Scala

Chcete-li testovat src/main/scala/example/MyUDF.scala, vytvořte testovací soubor v 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)
  }
}

Přidejte testovací závislost do build.sbt:

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

Spuštění testů:

sbt test

Java

Chcete-li testovat src/main/java/com/example/MyUDF.java, vytvořte testovací soubor v 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));
    }
}

Přidejte závislost JUnit do sekce <dependencies> v souboru pom.xml:

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

Spuštění testů:

mvn test

Dodatečné zdroje