Unit testing met testthat
Schrijf test_that()-blokken, gebruik expectations en voer tests uit met devtools::test().
Unit testing met testthat is een gratis R Academy-les op CoddyKit. Dit is les 3 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject R Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus R Academy bevat in totaal 4 lessen.
Waarom unittests?
Unittests controleren automatisch of afzonderlijke functies correct werken. Ze signaleren regressies wanneer je code wijzigt, dienen als uitvoerbare documentatie en geven je het vertrouwen om veilig te refactoren. Het pakket testthat is het standaardtestframework voor R-pakketten.
testthat instellen
usethis::use_testthat() voegt testthat toe aan Suggests in DESCRIPTION, maakt tests/testthat/ aan en maakt het uitvoerscript tests/testthat.R. Voer dit één keer uit bij het initialiseren van een nieuw pakket.
# 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: 3Een testbestand maken
usethis::use_test('add') maakt tests/testthat/test-add.R. Volgens de conventie krijgen testbestanden de naam test-{function_name}.R. Elk bestand groepeert tests voor één functie of functieonderdeel.
# 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)
# })Structuur van test_that()
test_that('description', { ... }) groepeert verwante verwachtingen. De beschrijving moet de zin 'test dat ...' aanvullen en specifiek genoeg zijn om nuttig te zijn in foutmeldingen.
# 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() en expect_identical()
expect_equal(actual, expected) test met een numerieke tolerantie voor drijvende komma's. expect_identical(actual, expected) vereist exacte gelijkheid, inclusief het type. In de meeste gevallen heeft expect_equal() de voorkeur.
# 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() en expect_warning()
Test of functies de juiste fouten en waarschuwingen produceren. Geef een regex-patroon door om de foutmelding te laten overeenkomen — zo weet je zeker dat de juiste fout wordt gegenereerd, en niet zomaar een fout.
# 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() en expect_false()
expect_true(expr) en expect_false(expr) testen logische voorwaarden. Gebruik ze bij het testen van predicaten of voorwaarden die één logische waarde retourneren.
# 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)
# })Meer verwachtingsfuncties
testthat biedt veel verwachtingsfuncties voor verschillende scenario's:
expect_length(x, n)— vectorlengte controlerenexpect_type(x, 'double')— basistype controlerenexpect_s3_class(x, 'data.frame')— S3-klasse controlerenexpect_null(x)— controleren op NULLexpect_match(string, regexp)— tekenreeks patroon controleren
# 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 uitvoeren met devtools::test()
devtools::test() (Ctrl+Shift+T) voert alle testbestanden uit en toont een samenvatting van geslaagde tests, fouten en waarschuwingen. Bij afzonderlijke testfouten zie je de verwachting die is mislukt en de werkelijke versus verwachte waarden.
# 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 ]Testdekking met covr
covr::package_coverage() meet welk percentage van de regels in je pakket door tests wordt uitgevoerd. covr::report() opent een HTML-rapport met gedekte (groene) en ongedekte (rode) regels. Streef naar een dekking van minstens 80%.
# 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 linesRandgevallen testen
Goede tests dekken niet alleen het normale pad, maar ook randgevallen:
- Lege invoer:
numeric(0),character(0) - NA-invoer: geeft de functie NA door of handelt ze die af?
- Invoer met lengte 1 tegenover invoer met lengte n
- Grenswaarden: 0, negatieve getallen, zeer grote waarden
- Onjuiste typen: wat gebeurt er wanneer de gebruiker een tekenreeks aan een numerieke functie doorgeeft?
# 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)
# })Korte controle: expect_error()
Je roept expect_error(my_fn('bad'), regexp = 'invalid input') aan. Wat controleert deze test?
Samenvatting van unit-tests
Een R-pakket testen met testthat:
usethis::use_testthat()— de testinfrastructuur eenmalig instellenusethis::use_test('fn')—tests/testthat/test-fn.Rmakentest_that('description', {...})— gerelateerde verwachtingen groeperenexpect_equal(),expect_error(),expect_warning(),expect_true(),expect_false()— de belangrijkste functies voor verwachtingendevtools::test()— alle tests uitvoeren (Ctrl+Shift+T)covr::package_coverage()— de testdekking meten
Leer R met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 43
- Lessen
- 159
Veelgestelde vragen
Is de les “Unit testing met testthat” gratis?
Ja — je kunt hier op het web alle 3 lessen van het leerpad R Academy, waaronder “Unit testing met testthat”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus R Academy bevat in totaal 4 lessen.
Wat leer ik in “Unit testing met testthat”?
Schrijf test_that()-blokken, gebruik expectations en voer tests uit met devtools::test(). Je oefent met R Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met R Academy te beginnen?
Ervaring vooraf is niet nodig. R Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 3 van 4.
Hoe lang duurt de les “Unit testing met testthat”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over R Academy?
Ja. Elke les over R Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Pakketstructuur met usethis en devtools
- Functies documenteren met roxygen2
- Unit testing met testthat
- CRAN-indiening en pakketonderhoud