Unit-Tests mit testthat
Schreiben Sie test_that()-Blöcke, verwenden Sie Expectations und führen Sie Tests mit devtools::test() aus
Unit-Tests mit testthat ist eine kostenlose R Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des R Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der R Academy-Kurs umfasst insgesamt 4 Lektionen.
Warum Unit-Tests?
Unit-Tests überprüfen automatisch, ob einzelne Funktionen korrekt funktionieren. Sie erkennen Regressionen bei Änderungen am Code, dienen als ausführbare Dokumentation und geben Ihnen Sicherheit, um Code gefahrlos umzustrukturieren. Das Paket testthat ist das Standard-Testing-Framework für R-Pakete.
testthat einrichten
usethis::use_testthat() fügt testthat in DESCRIPTION zu Suggests hinzu, erstellt tests/testthat/ und legt das Runner-Skript tests/testthat.R an. Führen Sie den Befehl einmal beim Initialisieren eines neuen Pakets aus.
# usethis::use_testthat()
#
# Creates:
# tests/
# testthat.R <- runner (do not edit)
# testthat/
# (empty — write test files here)
#
# Updates DESCRIPTION:
# Suggests: testthat (>= 3.0.0)
# Config/testthat/edition: 3Eine Testdatei erstellen
usethis::use_test('add') erstellt tests/testthat/test-add.R. Üblicherweise werden Testdateien test-{function_name}.R genannt. Jede Datei bündelt Tests für eine Funktion oder ein Feature.
# usethis::use_test('add') # creates tests/testthat/test-add.R
#
# Content of test-add.R:
# test_that('add() returns correct sum', {
# expect_equal(add(1, 2), 3)
# expect_equal(add(-1, 1), 0)
# expect_equal(add(0.1, 0.2), 0.3, tolerance = 1e-7)
# })Struktur von test_that()
test_that('description', { ... }) gruppiert zusammengehörige Erwartungen. Der Beschreibungstext sollte den Satz „test that …“ vervollständigen und spezifisch genug sein, um in Fehlermeldungen nützlich zu sein.
# Good test_that descriptions:
# test_that('add() handles negative numbers', { ... })
# test_that('add() recycles length-1 vectors', { ... })
# test_that('add() returns NA when input contains NA', { ... })
#
# Bad (too vague):
# test_that('it works', { ... })
# test_that('test1', { ... })expect_equal() und expect_identical()
expect_equal(actual, expected) prüft mit einer numerischen Toleranz für Gleitkommazahlen. expect_identical(actual, expected) verlangt exakte Gleichheit einschließlich des Typs. In den meisten Fällen ist expect_equal() vorzuziehen.
# test_that('add() adds correctly', {
# expect_equal(add(1, 2), 3) # numeric equality
# expect_equal(add(0.1, 0.2), 0.3) # tolerance handles floating point
# expect_identical(add(1L, 2L), 3L) # exact type match: integer
# expect_identical(add(1.0, 2.0), 3.0) # exact type match: double
# })expect_error() und expect_warning()
Prüfen Sie, ob Funktionen die richtigen Fehler und Warnungen erzeugen. Übergeben Sie ein Regex-Muster, das auf die Fehlermeldung passt — so wird sichergestellt, dass der richtige Fehler und nicht lediglich irgendein Fehler ausgelöst wird.
# test_that('add() validates input types', {
# expect_error(
# add('a', 2),
# regexp = 'numeric' # message must contain 'numeric'
# )
# expect_error(
# add(NULL, 1),
# regexp = 'numeric'
# )
# })
#
# test_that('sqrt() warns on negative input', {
# expect_warning(sqrt(-1))
# })expect_true() und expect_false()
expect_true(expr) und expect_false(expr) prüfen logische Bedingungen. Verwenden Sie sie beim Testen von Prädikaten oder Bedingungen, die einen einzelnen logischen Wert zurückgeben.
# test_that('is_positive() returns correct logical', {
# expect_true(is_positive(5))
# expect_true(is_positive(0.001))
# expect_false(is_positive(0))
# expect_false(is_positive(-3))
# })
#
# # Also useful for vector tests:
# test_that('add() result has correct length', {
# result <- add(c(1,2,3), c(4,5,6))
# expect_true(length(result) == 3)
# })Weitere Expectation-Funktionen
testthat stellt zahlreiche Expectation-Funktionen für verschiedene Szenarien bereit:
expect_length(x, n)— Vektorlänge prüfenexpect_type(x, 'double')— Basistyp prüfenexpect_s3_class(x, 'data.frame')— S3-Klasse prüfenexpect_null(x)— auf NULL prüfenexpect_match(string, regexp)— Zeichenfolgenmuster prüfen
# test_that('add() output has correct type and length', {
# result <- add(c(1.0, 2.0), c(3.0, 4.0))
# expect_type(result, 'double')
# expect_length(result, 2)
# })
#
# test_that('summary_stats() returns a data frame', {
# result <- summary_stats(rnorm(100))
# expect_s3_class(result, 'data.frame')
# })Tests mit devtools::test() ausführen
devtools::test() (Strg+Umschalt+T) führt alle Testdateien aus und zeigt eine Zusammenfassung der erfolgreichen Tests, Fehler und Warnungen an. Bei einzelnen fehlgeschlagenen Tests werden die fehlgeschlagene Erwartung sowie die tatsächlichen und erwarteten Werte angezeigt.
# devtools::test()
#
# Example output:
# == Testing mypackage ====================================
# v | OK F W S | Context
# v | 3 | add [0.1s]
# v | 4 | subtract [0.1s]
# x | 2 1 | multiply [0.2s]
# -- Failure (test-multiply.R:5): multiply() handles zero
# multiply(5, 0) not equal to 0.
# Actual: 5
# Expected: 0
# ==========================================================
# [ FAIL 1 | WARN 0 | SKIP 0 | PASS 9 ]Testabdeckung mit covr
covr::package_coverage() misst, welcher Prozentsatz der Zeilen Ihres Pakets durch Tests ausgeführt wird. covr::report() öffnet einen HTML-Bericht mit abgedeckten (grünen) und nicht abgedeckten (roten) Zeilen. Streben Sie eine Abdeckung von mindestens 80 % an.
# library(covr)
# cov <- package_coverage()
# print(cov)
#
# Example output:
# mypackage Coverage: 87.50%
# R/add.R: 100.00%
# R/subtract.R: 100.00%
# R/utils.R: 62.50% <- needs more tests!
#
# covr::report() # interactive HTML report
# covr::zero_coverage(cov) # list uncovered linesRandfälle testen
Gute Tests decken nicht nur den Normalfall, sondern auch Randfälle ab:
- Leere Eingaben:
numeric(0),character(0) - NA-Eingaben: Gibt die Funktion NA weiter oder behandelt sie den Wert?
- Eingaben der Länge 1 im Vergleich zu Eingaben der Länge n
- Grenzwerte: 0, negative Zahlen, sehr große Werte
- Falsche Typen: Was geschieht, wenn der Benutzer eine Zeichenfolge an eine numerische Funktion übergibt?
# test_that('add() handles edge cases', {
# expect_equal(add(numeric(0), numeric(0)), numeric(0)) # empty
# expect_true(is.na(add(NA, 1))) # NA propagation
# expect_equal(add(1, c(1,2,3)), c(2,3,4)) # recycling
# expect_equal(add(.Machine$integer.max, 0L), # boundary
# .Machine$integer.max)
# })Schnelltest: expect_error()
Sie rufen expect_error(my_fn('bad'), regexp = 'invalid input') auf. Was wird durch diesen Test überprüft?
Zusammenfassung: Unit-Tests
Testen eines R-Pakets mit testthat:
usethis::use_testthat()— richtet die Testinfrastruktur einmalig einusethis::use_test('fn')— erstellttests/testthat/test-fn.Rtest_that('description', {...})— gruppiert zusammengehörige Erwartungenexpect_equal(),expect_error(),expect_warning(),expect_true(),expect_false()— zentrale Erwartungsfunktionendevtools::test()— führt alle Tests aus (Strg+Umschalt+T)covr::package_coverage()— misst die Testabdeckung
Häufig gestellte Fragen
Ist die Lektion „Unit-Tests mit testthat“ kostenlos?
Ja — der vollständige Text von „Unit-Tests mit testthat“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des R Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der R Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Unit-Tests mit testthat“?
Schreiben Sie test_that()-Blöcke, verwenden Sie Expectations und führen Sie Tests mit devtools::test() aus Du übst R Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um R Academy zu starten?
Keine Vorkenntnisse erforderlich. R Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.
Wie lange dauert die Lektion „Unit-Tests mit testthat“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser R Academy-Lektion Code schreiben und ausführen?
Ja. Jede R Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Paketstruktur mit usethis und devtools
- Funktionen mit roxygen2 dokumentieren
- Unit-Tests mit testthat
- CRAN-Einreichung und Paketpflege