R Academy · Les

Unit testing met testthat

Schrijf test_that()-blokken, gebruik expectations en voer tests uit met devtools::test().

Les 3 van 413 stappen

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: 3

Een 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 controleren
  • expect_type(x, 'double') — basistype controleren
  • expect_s3_class(x, 'data.frame') — S3-klasse controleren
  • expect_null(x) — controleren op NULL
  • expect_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 lines

Randgevallen 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 instellen
  • usethis::use_test('fn') — tests/testthat/test-fn.R maken
  • test_that('description', {...}) — gerelateerde verwachtingen groeperen
  • expect_equal(), expect_error(), expect_warning(), expect_true(), expect_false() — de belangrijkste functies voor verwachtingen
  • devtools::test() — alle tests uitvoeren (Ctrl+Shift+T)
  • covr::package_coverage() — de testdekking meten
Gratis beginnen

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

  1. Pakketstructuur met usethis en devtools
  2. Functies documenteren met roxygen2
  3. Unit testing met testthat
  4. CRAN-indiening en pakketonderhoud
← Terug naar R Academy