Tests unitaires avec testthat
Écrivez des blocs test_that(), utilisez des attentes et exécutez les tests avec devtools::test().
Tests unitaires avec testthat est une leçon R Academy gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage R Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours R Academy comprend 4 leçons au total.
Pourquoi effectuer des tests unitaires ?
Les tests unitaires vérifient automatiquement que chaque fonction se comporte correctement. Ils détectent les régressions lorsque vous modifiez le code, servent de documentation exécutable et vous donnent confiance pour remanier le code en toute sécurité. Le package testthat est le framework de test standard pour les packages R.
Configurer testthat
usethis::use_testthat() ajoute testthat à Suggests dans DESCRIPTION, crée tests/testthat/ et crée le script d’exécution tests/testthat.R. Exécutez cette commande une fois lors de l’initialisation d’un nouveau package.
# 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: 3Créer un fichier de test
usethis::use_test('add') crée tests/testthat/test-add.R. Par convention, les fichiers de test sont nommés test-{function_name}.R. Chaque fichier regroupe les tests d’une fonction ou d’une fonctionnalité.
# 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)
# })Structure de test_that()
test_that('description', { ... }) regroupe des attentes apparentées. La chaîne de description doit compléter la phrase « testez que… » et être suffisamment précise pour être utile dans les messages d’échec.
# 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() et expect_identical()
expect_equal(actual, expected) effectue une comparaison avec une tolérance numérique pour les nombres à virgule flottante. expect_identical(actual, expected) exige une égalité exacte, y compris le type. Dans la plupart des cas, expect_equal() est préférable.
# 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() et expect_warning()
Vérifiez que les fonctions produisent les erreurs et les avertissements corrects. Transmettez un motif d’expression régulière pour faire correspondre le message d’erreur : cela garantit qu’il s’agit de la bonne erreur, et pas simplement d’une erreur quelconque.
# 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() et expect_false()
expect_true(expr) et expect_false(expr) testent des conditions logiques. Utilisez-les pour tester des prédicats ou des conditions qui renvoient une seule valeur logique.
# 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)
# })Autres fonctions d’attente
testthat fournit de nombreuses fonctions d’attente pour différents cas :
expect_length(x, n)— vérifier la longueur d’un vecteurexpect_type(x, 'double')— vérifier le type de baseexpect_s3_class(x, 'data.frame')— vérifier la classe S3expect_null(x)— vérifier qu’une valeur est NULLexpect_match(string, regexp)— vérifier un motif dans une chaîne
# 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')
# })Exécuter les tests avec devtools::test()
devtools::test() (Ctrl+Shift+T) exécute tous les fichiers de test et affiche un résumé des réussites, des échecs et des avertissements. Pour chaque échec, le test indique l’attente qui a échoué ainsi que les valeurs réelles et attendues.
# 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 ]Couverture des tests avec covr
covr::package_coverage() mesure le pourcentage de lignes de votre package exécutées par les tests. covr::report() ouvre un rapport HTML présentant les lignes couvertes (en vert) et non couvertes (en rouge). Visez une couverture d’au moins 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 linesTester les cas limites
De bons tests couvrent non seulement le parcours nominal, mais aussi les cas limites :
- Entrées vides :
numeric(0),character(0) - Entrées NA : la fonction propage-t-elle ou gère-t-elle NA ?
- Entrées de longueur 1 et de longueur n
- Valeurs limites : 0, nombres négatifs, valeurs très grandes
- Types incorrects : que se passe-t-il lorsque l’utilisateur transmet une chaîne à une fonction numérique ?
# 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)
# })Vérification rapide : expect_error()
Vous appelez expect_error(my_fn('bad'), regexp = 'invalid input'). Que vérifie ce test ?
Récapitulatif des tests unitaires
Tester un paquet R avec testthat :
usethis::use_testthat()— configurer une fois l'infrastructure de testusethis::use_test('fn')— créertests/testthat/test-fn.Rtest_that('description', {...})— regrouper les attentes associéesexpect_equal(),expect_error(),expect_warning(),expect_true(),expect_false()— fonctions principales d'attentedevtools::test()— exécuter tous les tests (Ctrl+Maj+T)covr::package_coverage()— mesurer la couverture des tests
Questions Fréquemment Posées
La leçon « Tests unitaires avec testthat » est-elle gratuite ?
Oui — le texte complet de « Tests unitaires avec testthat » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours R Academy, passe à CoddyKit PRO. Le cours R Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Tests unitaires avec testthat » ?
Écrivez des blocs test_that(), utilisez des attentes et exécutez les tests avec devtools::test(). Tu pratiques R Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer R Academy ?
Aucune expérience préalable n'est requise. R Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.
Combien de temps prend la leçon « Tests unitaires avec testthat » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon R Academy ?
Oui. Chaque leçon R Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Structure d’un paquet avec usethis et devtools
- Documenter des fonctions avec roxygen2
- Tests unitaires avec testthat
- Soumission à CRAN et maintenance des paquets