Eenheidstests voor notebooks
U kunt eenheidstests gebruiken om de kwaliteit en consistentie van de code van uw notebooks te verbeteren. Eenheidstests zijn een benadering voor het testen van zelfstandige code-eenheden, zoals functies, vroeg en vaak. Zo kunt u sneller problemen met uw code vinden, foute veronderstellingen over uw code sneller ontdekken en uw algehele code-inspanningen stroomlijnen.
Dit artikel is een inleiding tot basis unittesten met functies. Geavanceerde concepten, zoals klassen en interfaces voor eenheidstests, evenals het gebruik van stubs, mocks, en testharnassen, hoewel deze ook bij eenheidstests voor notebooks worden ondersteund, vallen buiten het bestek van dit artikel. Dit artikel omvat ook geen andere soorten testmethoden, zoals integratietests, systeemtests, acceptatietestsof niet-functionele tests methoden zoals prestatietests of bruikbaarheidstests.
In dit artikel ziet u het volgende:
- Functies en hun eenheidstests organiseren.
- Functies schrijven in Python, R, Scala en door de gebruiker gedefinieerde functies in SQL, die goed zijn ontworpen om te worden getest.
- Deze functies aanroepen vanuit Python-, R-, Scala- en SQL-notebooks.
- Eenheidstests schrijven in Python, R en Scala met behulp van de populaire testframeworks pytest- voor Python, testthat voor R en ScalaTest voor Scala. Ook hoe u SQL schrijft die eenheid SQL door de gebruiker gedefinieerde functies (SQL UDF's) test.
- Deze eenheidstests uitvoeren vanuit Python-, R-, Scala- en SQL-notebooks.
Notitie
Azure Databricks raadt u aan uw eenheidstests in een notebook te schrijven en uit te voeren. Hoewel u bepaalde opdrachten in de webterminal kunt uitvoeren, heeft de webterminal meer beperkingen, zoals een gebrek aan ondersteuning voor Spark. Zie Shell-opdrachten uitvoeren in de Azure Databricks-webterminal.
Functies en eenheidstests organiseren
Er zijn enkele algemene benaderingen voor het ordenen van uw functies en hun unittests in notebooks. Elke aanpak heeft zijn voordelen en uitdagingen.
Voor Python-, R- en Scala-notebooks zijn veelvoorkomende benaderingen het volgende:
-
Store-functies en de bijbehorende eenheidstests buiten notebooks..
- Voordelen: U kunt deze functies aanroepen met en buiten notebooks. Testframeworks zijn beter ontworpen om tests buiten notebooks uit te voeren.
- Uitdagingen: deze benadering wordt niet ondersteund voor Scala-notebooks. Deze aanpak verhoogt ook het aantal bestanden dat moet worden bijgehouden en onderhouden.
-
Store-functies in één notebook en de bijbehorende unittests in een afzonderlijk notebook..
- Voordelen: Deze functies zijn eenvoudiger te hergebruiken in notebooks.
- Uitdagingen: het aantal notebooks dat moet worden bijgehouden en onderhouden, neemt toe. Deze functies kunnen niet buiten notebooks worden gebruikt. Deze functies kunnen ook lastiger te testen zijn buiten notebooks.
-
Store-functies en de bijbehorende unittests binnen hetzelfde notebook..
- Voordelen: Functies en hun eenheidstests worden opgeslagen in één notebook voor eenvoudiger bijhouden en onderhouden.
- Uitdagingen: deze functies kunnen moeilijker opnieuw worden gebruikt in notebooks. Deze functies kunnen niet buiten notebooks worden gebruikt. Deze functies kunnen ook lastiger te testen zijn buiten notebooks.
Voor Python- en R-notebooks raadt Databricks aan om functies en hun eenheidstests buiten notebooks op te slaan. Voor Scala-notebooks raadt Databricks aan om functies in één notebook en de bijbehorende eenheidstests in een afzonderlijk notebook op te geven.
Voor SQL-notebooks raadt Databricks u aan om functies op te slaan als door de gebruiker gedefinieerde SQL-functies (SQL UDF's) in uw schema's (ook wel databases genoemd). U kunt deze SQL UDF's en de bijbehorende eenheidstests vervolgens aanroepen vanuit SQL-notebooks.
Schrijffuncties
In deze sectie wordt een eenvoudige set voorbeeldfuncties beschreven die het volgende bepalen:
- Of er een tabel in een database bestaat.
- Of er een kolom in een tabel bestaat.
- Het aantal rijen in een kolom voor een waarde in die kolom.
Deze functies zijn bedoeld om eenvoudig te zijn, zodat u zich kunt richten op de details van het testen van eenheden in dit artikel in plaats van zich te richten op de functies zelf.
Als u de beste resultaten van het testen van eenheden wilt ophalen, moet een functie één voorspelbaar resultaat retourneren en van één gegevenstype zijn. Als u bijvoorbeeld wilt controleren of er iets bestaat, moet de functie een Booleaanse waarde van waar of onwaar retourneren. Als u het aantal rijen wilt retourneren dat bestaat, moet de functie een niet-negatief geheel getal retourneren. In het eerste voorbeeld moet dit niet onwaar retourneren als er iets niet bestaat of het ding zelf als het wel bestaat. Voor het tweede voorbeeld mag het niet het aantal rijen retourneren dat bestaat of onwaar als er geen rijen bestaan.
U kunt deze functies als volgt toevoegen aan een bestaande Azure Databricks-werkruimte in Python, R, Scala of SQL.
Python
In de volgende code wordt ervan uitgegaan dat u Databricks Git-mappen (opslagplaatsen) hebt ingesteld, een opslagplaatshebt toegevoegd en dat de opslagplaats is geopend in uw Azure Databricks-werkruimte.
Maak een bestand met de naam myfunctions.py
in de opslagplaats en voeg de volgende inhoud toe aan het bestand. In andere voorbeelden in dit artikel wordt verwacht dat dit bestand de naam myfunctions.py
heeft. U kunt verschillende namen gebruiken voor uw eigen bestanden.
import pyspark
from pyspark.sql import SparkSession
from pyspark.sql.functions import col
# Because this file is not a Databricks notebook, you
# must create a Spark session. Databricks notebooks
# create a Spark session for you by default.
spark = SparkSession.builder \
.appName('integrity-tests') \
.getOrCreate()
# Does the specified table exist in the specified database?
def tableExists(tableName, dbName):
return spark.catalog.tableExists(f"{dbName}.{tableName}")
# Does the specified column exist in the given DataFrame?
def columnExists(dataFrame, columnName):
if columnName in dataFrame.columns:
return True
else:
return False
# How many rows are there for the specified value in the specified column
# in the given DataFrame?
def numRowsInColumnForValue(dataFrame, columnName, columnValue):
df = dataFrame.filter(col(columnName) == columnValue)
return df.count()
R
In de volgende code wordt ervan uitgegaan dat u Databricks Git-mappen (opslagplaatsen) hebt ingesteld, een opslagplaatshebt toegevoegd en dat de opslagplaats is geopend in uw Azure Databricks-werkruimte.
Maak een bestand met de naam myfunctions.r
in de opslagplaats en voeg de volgende inhoud toe aan het bestand. In andere voorbeelden in dit artikel wordt verwacht dat dit bestand de naam myfunctions.r
heeft. U kunt verschillende namen gebruiken voor uw eigen bestanden.
library(SparkR)
# Does the specified table exist in the specified database?
table_exists <- function(table_name, db_name) {
tableExists(paste(db_name, ".", table_name, sep = ""))
}
# Does the specified column exist in the given DataFrame?
column_exists <- function(dataframe, column_name) {
column_name %in% colnames(dataframe)
}
# How many rows are there for the specified value in the specified column
# in the given DataFrame?
num_rows_in_column_for_value <- function(dataframe, column_name, column_value) {
df = filter(dataframe, dataframe[[column_name]] == column_value)
count(df)
}
Scala
Maak een Scala-notebook met de naam myfunctions
met de volgende inhoud. In andere voorbeelden in dit artikel wordt verwacht dat dit notitieblok de naam myfunctions
heeft. U kunt verschillende namen gebruiken voor uw eigen notitieblokken.
import org.apache.spark.sql.DataFrame
import org.apache.spark.sql.functions.col
// Does the specified table exist in the specified database?
def tableExists(tableName: String, dbName: String) : Boolean = {
return spark.catalog.tableExists(dbName + "." + tableName)
}
// Does the specified column exist in the given DataFrame?
def columnExists(dataFrame: DataFrame, columnName: String) : Boolean = {
val nameOfColumn = null
for(nameOfColumn <- dataFrame.columns) {
if (nameOfColumn == columnName) {
return true
}
}
return false
}
// How many rows are there for the specified value in the specified column
// in the given DataFrame?
def numRowsInColumnForValue(dataFrame: DataFrame, columnName: String, columnValue: String) : Long = {
val df = dataFrame.filter(col(columnName) === columnValue)
return df.count()
}
SQL
In de volgende code wordt ervan uitgegaan dat u de voorbeeldgegevensset van derden hebt diamanten binnen een schema met de naam default
in een catalogus met de naam main
die toegankelijk is vanuit uw Azure Databricks-werkruimte. Als de catalogus of het schema dat u wilt gebruiken een andere naam heeft, wijzigt u een of beide van de volgende USE
instructies zodat deze overeenkomen.
Maak een SQL-notebook en voeg de volgende inhoud toe aan dit nieuwe notebook. Sluit het notitieboekje aan op een cluster en voer het notitieboekje uit om de volgende SQL UDF's aan de opgegeven catalogus en het opgegeven schema toe te voegen.
Notitie
De SQL UDF's table_exists
en column_exists
werken alleen met Unity Catalog. SQL UDF-ondersteuning voor Unity Catalog bevindt zich in openbare versie.
USE CATALOG main;
USE SCHEMA default;
CREATE OR REPLACE FUNCTION table_exists(catalog_name STRING,
db_name STRING,
table_name STRING)
RETURNS BOOLEAN
RETURN if(
(SELECT count(*) FROM system.information_schema.tables
WHERE table_catalog = table_exists.catalog_name
AND table_schema = table_exists.db_name
AND table_name = table_exists.table_name) > 0,
true,
false
);
CREATE OR REPLACE FUNCTION column_exists(catalog_name STRING,
db_name STRING,
table_name STRING,
column_name STRING)
RETURNS BOOLEAN
RETURN if(
(SELECT count(*) FROM system.information_schema.columns
WHERE table_catalog = column_exists.catalog_name
AND table_schema = column_exists.db_name
AND table_name = column_exists.table_name
AND column_name = column_exists.column_name) > 0,
true,
false
);
CREATE OR REPLACE FUNCTION num_rows_for_clarity_in_diamonds(clarity_value STRING)
RETURNS BIGINT
RETURN SELECT count(*)
FROM main.default.diamonds
WHERE clarity = clarity_value
Aanroepfuncties
In deze sectie wordt code beschreven die de voorgaande functies aanroept. U kunt deze functies bijvoorbeeld gebruiken om het aantal rijen in een tabel te tellen waarin een opgegeven waarde bestaat binnen een opgegeven kolom. U wilt echter controleren of de tabel daadwerkelijk bestaat en of de kolom daadwerkelijk in die tabel bestaat voordat u verdergaat. Met de volgende code wordt gecontroleerd op deze voorwaarden.
Als u de functies uit de vorige sectie hebt toegevoegd aan uw Azure Databricks-werkruimte, kunt u deze functies als volgt vanuit uw werkruimte aanroepen.
Python
Maak een Python-notebook in dezelfde map als het voorgaande myfunctions.py
-bestand in uw opslagplaats en voeg de volgende inhoud toe aan het notitieblok. Wijzig de variabelewaarden voor de tabelnaam, de schemanaam (database), de kolomnaam en de kolomwaarde indien nodig. Voeg het notebook toe aan een cluster en het notebook uitvoeren om de resultaten te bekijken.
from myfunctions import *
tableName = "diamonds"
dbName = "default"
columnName = "clarity"
columnValue = "VVS2"
# If the table exists in the specified database...
if tableExists(tableName, dbName):
df = spark.sql(f"SELECT * FROM {dbName}.{tableName}")
# And the specified column exists in that table...
if columnExists(df, columnName):
# Then report the number of rows for the specified value in that column.
numRows = numRowsInColumnForValue(df, columnName, columnValue)
print(f"There are {numRows} rows in '{tableName}' where '{columnName}' equals '{columnValue}'.")
else:
print(f"Column '{columnName}' does not exist in table '{tableName}' in schema (database) '{dbName}'.")
else:
print(f"Table '{tableName}' does not exist in schema (database) '{dbName}'.")
R
Maak een R-notebook in dezelfde map als het voorgaande myfunctions.r
-bestand in uw opslagplaats en voeg de volgende inhoud toe aan het notitieblok. Wijzig de variabelewaarden voor de tabelnaam, de schemanaam (database), de kolomnaam en de kolomwaarde indien nodig. Bevestig een notebook aan een cluster en voer het notebook uit om de resultaten te bekijken.
library(SparkR)
source("myfunctions.r")
table_name <- "diamonds"
db_name <- "default"
column_name <- "clarity"
column_value <- "VVS2"
# If the table exists in the specified database...
if (table_exists(table_name, db_name)) {
df = sql(paste("SELECT * FROM ", db_name, ".", table_name, sep = ""))
# And the specified column exists in that table...
if (column_exists(df, column_name)) {
# Then report the number of rows for the specified value in that column.
num_rows = num_rows_in_column_for_value(df, column_name, column_value)
print(paste("There are ", num_rows, " rows in table '", table_name, "' where '", column_name, "' equals '", column_value, "'.", sep = ""))
} else {
print(paste("Column '", column_name, "' does not exist in table '", table_name, "' in schema (database) '", db_name, "'.", sep = ""))
}
} else {
print(paste("Table '", table_name, "' does not exist in schema (database) '", db_name, "'.", sep = ""))
}
Scala
Maak een ander Scala-notitieblok in dezelfde map als het voorgaande myfunctions
Scala-notebook en voeg de volgende inhoud toe aan dit nieuwe notitieblok.
Voeg in de eerste cel van dit nieuwe notebook de volgende code toe, die de %run magie aanroept. Deze magic maakt de inhoud van het myfunctions
notebook beschikbaar voor uw nieuwe notebook.
%run ./myfunctions
Voeg in de tweede cel van dit nieuwe notitieblok de volgende code toe. Wijzig de variabelewaarden voor de tabelnaam, de schemanaam (database), de kolomnaam en de kolomwaarde indien nodig. Voeg het notebook toe aan een cluster en voer het notebook uit om de resultaten te bekijken.
val tableName = "diamonds"
val dbName = "default"
val columnName = "clarity"
val columnValue = "VVS2"
// If the table exists in the specified database...
if (tableExists(tableName, dbName)) {
val df = spark.sql("SELECT * FROM " + dbName + "." + tableName)
// And the specified column exists in that table...
if (columnExists(df, columnName)) {
// Then report the number of rows for the specified value in that column.
val numRows = numRowsInColumnForValue(df, columnName, columnValue)
println("There are " + numRows + " rows in '" + tableName + "' where '" + columnName + "' equals '" + columnValue + "'.")
} else {
println("Column '" + columnName + "' does not exist in table '" + tableName + "' in database '" + dbName + "'.")
}
} else {
println("Table '" + tableName + "' does not exist in database '" + dbName + "'.")
}
SQL
Voeg de volgende code toe aan een nieuwe cel in het voorgaande notitieblok of aan een cel in een afzonderlijk notitieblok. Wijzig zo nodig de schema- of catalogusnamen zodat deze overeenkomt met die van u en voer deze cel uit om de resultaten te bekijken.
SELECT CASE
-- If the table exists in the specified catalog and schema...
WHEN
table_exists("main", "default", "diamonds")
THEN
-- And the specified column exists in that table...
(SELECT CASE
WHEN
column_exists("main", "default", "diamonds", "clarity")
THEN
-- Then report the number of rows for the specified value in that column.
printf("There are %d rows in table 'main.default.diamonds' where 'clarity' equals 'VVS2'.",
num_rows_for_clarity_in_diamonds("VVS2"))
ELSE
printf("Column 'clarity' does not exist in table 'main.default.diamonds'.")
END)
ELSE
printf("Table 'main.default.diamonds' does not exist.")
END
Eenheidstests schrijven
In deze sectie wordt code beschreven waarmee alle functies worden getest die aan het begin van dit artikel worden beschreven. Als u in de toekomst wijzigingen aanbrengt in functies, kunt u eenheidstests gebruiken om te bepalen of deze functies nog steeds werken zoals verwacht.
Als u de functies aan het begin van dit artikel hebt toegevoegd aan uw Azure Databricks-werkruimte, kunt u als volgt eenheidstests voor deze functies aan uw werkruimte toevoegen.
Python
Maak een ander bestand met de naam test_myfunctions.py
in dezelfde map als het voorgaande myfunctions.py
-bestand in uw opslagplaats en voeg de volgende inhoud toe aan het bestand. Standaard zoekt pytest
naar .py
bestanden waarvan de namen beginnen met test_
(of eindigen met _test
) om te testen. Op dezelfde manier kijkt pytest
standaard in deze bestanden naar functies waarvan de namen beginnen met test_
om te testen.
Over het algemeen is het een goede praktijk om geen unittests uit te voeren op functies die met gegevens in productie werken. Dit is met name belangrijk voor functies die gegevens toevoegen, verwijderen of anderszins wijzigen. Als u uw productiegegevens op onverwachte manieren wilt beschermen tegen inbreuk op uw eenheidstests, moet u eenheidstests uitvoeren op niet-productiegegevens. Een veelvoorkomende aanpak is om valse gegevens te maken die zo dicht mogelijk bij de productiegegevens liggen. In het volgende codevoorbeeld worden valse gegevens gemaakt voor de eenheidstests waarop moet worden uitgevoerd.
import pytest
import pyspark
from myfunctions import *
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StructField, IntegerType, FloatType, StringType
tableName = "diamonds"
dbName = "default"
columnName = "clarity"
columnValue = "SI2"
# Because this file is not a Databricks notebook, you
# must create a Spark session. Databricks notebooks
# create a Spark session for you by default.
spark = SparkSession.builder \
.appName('integrity-tests') \
.getOrCreate()
# Create fake data for the unit tests to run against.
# In general, it is a best practice to not run unit tests
# against functions that work with data in production.
schema = StructType([ \
StructField("_c0", IntegerType(), True), \
StructField("carat", FloatType(), True), \
StructField("cut", StringType(), True), \
StructField("color", StringType(), True), \
StructField("clarity", StringType(), True), \
StructField("depth", FloatType(), True), \
StructField("table", IntegerType(), True), \
StructField("price", IntegerType(), True), \
StructField("x", FloatType(), True), \
StructField("y", FloatType(), True), \
StructField("z", FloatType(), True), \
])
data = [ (1, 0.23, "Ideal", "E", "SI2", 61.5, 55, 326, 3.95, 3.98, 2.43 ), \
(2, 0.21, "Premium", "E", "SI1", 59.8, 61, 326, 3.89, 3.84, 2.31 ) ]
df = spark.createDataFrame(data, schema)
# Does the table exist?
def test_tableExists():
assert tableExists(tableName, dbName) is True
# Does the column exist?
def test_columnExists():
assert columnExists(df, columnName) is True
# Is there at least one row for the value in the specified column?
def test_numRowsInColumnForValue():
assert numRowsInColumnForValue(df, columnName, columnValue) > 0
R
Maak een ander bestand met de naam test_myfunctions.r
in dezelfde map als het voorgaande myfunctions.r
-bestand in uw opslagplaats en voeg de volgende inhoud toe aan het bestand. Standaard zoekt testthat
naar .r
bestanden waarvan de namen beginnen met test
om te testen.
Over het algemeen is het een best practice om niet te moduletests uit te voeren op functies die met gegevens in productie werken. Dit is met name belangrijk voor functies die gegevens toevoegen, verwijderen of anderszins wijzigen. Als u uw productiegegevens op onverwachte manieren wilt beschermen tegen inbreuk op uw eenheidstests, moet u eenheidstests uitvoeren op niet-productiegegevens. Een veelvoorkomende aanpak is om valse gegevens te maken die zo dicht mogelijk bij de productiegegevens liggen. In het volgende codevoorbeeld worden nepgegevens gemaakt voor de unittests om tegen te testen.
library(testthat)
source("myfunctions.r")
table_name <- "diamonds"
db_name <- "default"
column_name <- "clarity"
column_value <- "SI2"
# Create fake data for the unit tests to run against.
# In general, it is a best practice to not run unit tests
# against functions that work with data in production.
schema <- structType(
structField("_c0", "integer"),
structField("carat", "float"),
structField("cut", "string"),
structField("color", "string"),
structField("clarity", "string"),
structField("depth", "float"),
structField("table", "integer"),
structField("price", "integer"),
structField("x", "float"),
structField("y", "float"),
structField("z", "float"))
data <- list(list(as.integer(1), 0.23, "Ideal", "E", "SI2", 61.5, as.integer(55), as.integer(326), 3.95, 3.98, 2.43),
list(as.integer(2), 0.21, "Premium", "E", "SI1", 59.8, as.integer(61), as.integer(326), 3.89, 3.84, 2.31))
df <- createDataFrame(data, schema)
# Does the table exist?
test_that ("The table exists.", {
expect_true(table_exists(table_name, db_name))
})
# Does the column exist?
test_that ("The column exists in the table.", {
expect_true(column_exists(df, column_name))
})
# Is there at least one row for the value in the specified column?
test_that ("There is at least one row in the query result.", {
expect_true(num_rows_in_column_for_value(df, column_name, column_value) > 0)
})
Scala
Maak een ander Scala-notitieblok in dezelfde map als het voorgaande myfunctions
Scala-notebook en voeg de volgende inhoud toe aan dit nieuwe notitieblok.
Voeg in de eerste cel van het nieuwe notitieblok de volgende code toe, waarmee je de %run
-magic aanroept. Deze magische functie maakt de inhoud van het myfunctions
-notitieboek beschikbaar voor uw nieuwe notitieboek.
%run ./myfunctions
Voeg in de tweede cel de volgende code toe. Deze code definieert uw eenheidstests en geeft aan hoe u deze kunt uitvoeren.
Over het algemeen is het een best practice om niet te moduletests uit te voeren op functies die met gegevens in productie werken. Dit is met name belangrijk voor functies die gegevens toevoegen, verwijderen of anderszins wijzigen. Als u uw productiegegevens op onverwachte manieren wilt beschermen tegen inbreuk op uw eenheidstests, moet u eenheidstests uitvoeren op niet-productiegegevens. Een veelvoorkomende aanpak is om valse gegevens te maken die zo dicht mogelijk bij de productiegegevens liggen. Het volgende codevoorbeeld maakt nepgegevens aan waarop de unittests vervolgens worden uitgevoerd.
import org.scalatest._
import org.apache.spark.sql.types.{StructType, StructField, IntegerType, FloatType, StringType}
import scala.collection.JavaConverters._
class DataTests extends AsyncFunSuite {
val tableName = "diamonds"
val dbName = "default"
val columnName = "clarity"
val columnValue = "SI2"
// Create fake data for the unit tests to run against.
// In general, it is a best practice to not run unit tests
// against functions that work with data in production.
val schema = StructType(Array(
StructField("_c0", IntegerType),
StructField("carat", FloatType),
StructField("cut", StringType),
StructField("color", StringType),
StructField("clarity", StringType),
StructField("depth", FloatType),
StructField("table", IntegerType),
StructField("price", IntegerType),
StructField("x", FloatType),
StructField("y", FloatType),
StructField("z", FloatType)
))
val data = Seq(
Row(1, 0.23, "Ideal", "E", "SI2", 61.5, 55, 326, 3.95, 3.98, 2.43),
Row(2, 0.21, "Premium", "E", "SI1", 59.8, 61, 326, 3.89, 3.84, 2.31)
).asJava
val df = spark.createDataFrame(data, schema)
// Does the table exist?
test("The table exists") {
assert(tableExists(tableName, dbName) == true)
}
// Does the column exist?
test("The column exists") {
assert(columnExists(df, columnName) == true)
}
// Is there at least one row for the value in the specified column?
test("There is at least one matching row") {
assert(numRowsInColumnForValue(df, columnName, columnValue) > 0)
}
}
nocolor.nodurations.nostacks.stats.run(new DataTests)
Notitie
In dit codevoorbeeld wordt de FunSuite
stijl voor testen in ScalaTest gebruikt. Zie Teststijlen selecteren voor uw projectvoor andere beschikbare teststijlen.
SQL
Voordat u eenheidstests toevoegt, moet u er rekening mee houden dat het in het algemeen een best practice is om niet te
Als u een weergave wilt maken, kunt u de opdracht CREATE VIEW aanroepen vanuit een nieuwe cel in het voorgaande notitieblok of een afzonderlijk notitieblok. In het volgende voorbeeld wordt ervan uitgegaan dat u een bestaande tabel hebt met de naam diamonds
binnen een schema (database) met de naam default
in een catalogus met de naam main
. Wijzig deze namen zodat ze overeenkomen met uw eigen namen en voer dan alleen die cel uit.
USE CATALOG main;
USE SCHEMA default;
CREATE VIEW view_diamonds AS
SELECT * FROM diamonds;
Nadat u de weergave hebt gemaakt, voegt u elk van de volgende SELECT
instructies toe aan een eigen nieuwe cel in het voorgaande notitieblok of aan een eigen nieuwe cel in een afzonderlijk notitieblok. Wijzig de namen zodat deze overeenkomen met uw eigen namen.
SELECT if(table_exists("main", "default", "view_diamonds"),
printf("PASS: The table 'main.default.view_diamonds' exists."),
printf("FAIL: The table 'main.default.view_diamonds' does not exist."));
SELECT if(column_exists("main", "default", "view_diamonds", "clarity"),
printf("PASS: The column 'clarity' exists in the table 'main.default.view_diamonds'."),
printf("FAIL: The column 'clarity' does not exists in the table 'main.default.view_diamonds'."));
SELECT if(num_rows_for_clarity_in_diamonds("VVS2") > 0,
printf("PASS: The table 'main.default.view_diamonds' has at least one row where the column 'clarity' equals 'VVS2'."),
printf("FAIL: The table 'main.default.view_diamonds' does not have at least one row where the column 'clarity' equals 'VVS2'."));
Eenheidstests uitvoeren
In deze sectie wordt beschreven hoe u de eenheidstests uitvoert die u in de vorige sectie hebt gecodeerd. Wanneer u de eenheidstests uitvoert, krijgt u resultaten die laten zien welke eenheidstests zijn geslaagd en mislukt.
Als u de eenheidstests uit de vorige sectie hebt toegevoegd aan uw Azure Databricks-werkruimte, kunt u deze eenheidstests uitvoeren vanuit uw werkruimte. U kunt deze eenheidstests uitvoeren handmatig of volgens een planning.
Python
Maak een Python-notebook in dezelfde map als het voorgaande test_myfunctions.py
-bestand in uw opslagplaats en voeg de volgende inhoud toe.
Voeg in de eerste cel van het nieuwe notitieblok de volgende code toe en voer de cel vervolgens uit, die de %pip
-magic aanroept. Dit trucje installeert pytest
.
%pip install pytest
Voeg in de tweede cel de volgende code toe en voer vervolgens de cel uit. Resultaten geven aan welke eenheidstests zijn geslaagd en mislukt.
import pytest
import sys
# Skip writing pyc files on a readonly filesystem.
sys.dont_write_bytecode = True
# Run pytest.
retcode = pytest.main([".", "-v", "-p", "no:cacheprovider"])
# Fail the cell execution if there are any test failures.
assert retcode == 0, "The pytest invocation failed. See the log for details."
R
Maak een R-notebook in dezelfde map als het voorgaande test_myfunctions.r
-bestand in uw opslagplaats en voeg de volgende inhoud toe.
Voeg in de eerste cel de volgende code toe en voer vervolgens de cel uit, waarmee de functie install.packages
wordt aangeroepen. Met deze functie wordt testthat
geïnstalleerd.
install.packages("testthat")
Voeg in de tweede cel de volgende code toe en voer vervolgens de cel uit. Resultaten geven aan welke eenheidstests zijn geslaagd en mislukt.
library(testthat)
source("myfunctions.r")
test_dir(".", reporter = "tap")
Scala
Voer eerst de eerste en dan de tweede cel in het notitieboek uit uit de vorige sectie. Resultaten geven aan welke eenheidstests zijn geslaagd en mislukt.
SQL
Voer elk van de drie cellen in het notebook uit vanuit de vorige sectie. De resultaten geven aan of elke eenheidstest is geslaagd of mislukt.
Als u de weergave niet meer nodig hebt nadat u de eenheidstests hebt uitgevoerd, kunt u de weergave verwijderen. Als u deze weergave wilt verwijderen, kunt u de volgende code toevoegen aan een nieuwe cel in een van de voorgaande notebooks en vervolgens alleen die cel uitvoeren.
DROP VIEW view_diamonds;
Tip
U kunt de resultaten van uw notebookuitvoeringen (inclusief eenheidstestresultaten) bekijken in de stuurprogrammalogboeken van uw cluster. U kunt ook een locatie opgeven voor de logboeklevering van uw cluster.
U kunt een systeem voor continue integratie en continue levering of implementatie (CI/CD), zoals GitHub Actions, instellen om uw eenheidstests automatisch uit te voeren wanneer uw code wordt gewijzigd. Zie de bespreking van GitHub Actions in best practices voor software-engineering voor notebooksvoor een voorbeeld.
Aanvullende informatiebronnen
pytest
- pytest-startpagina
- pytest handleidingen
- pytest-referentiehandleidingen
- best practices voor software-engineering voor notebooks
testthat
ScalaTest
- scalatest-startpagina
- ScalaTest-gebruikershandleiding
- Scaladoc-documentatie van ScalaTest