0Pricing
R Academy · Lección

Pruebas unitarias con testthat

Escriba bloques test_that(), use expectations y ejecute pruebas con devtools::test().

Pruebas unitarias con testthat es una lección gratuita de R Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de R Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de R Academy incluye 4 lecciones en total.

¿Por qué realizar pruebas unitarias?

Las pruebas unitarias verifican automáticamente que las funciones individuales se comporten correctamente. Detectan regresiones al modificar el código, sirven como documentación ejecutable y le dan confianza para refactorizar de forma segura. El paquete testthat es el framework de pruebas estándar para los paquetes de R.

Configurar testthat

usethis::use_testthat() añade testthat a Suggests en DESCRIPTION, crea tests/testthat/ y crea el script ejecutor tests/testthat.R. Ejecútelo una vez al inicializar un paquete nuevo.

# 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

Crear un archivo de pruebas

usethis::use_test('add') crea tests/testthat/test-add.R. Por convención, los archivos de pruebas se nombran test-{function_name}.R. Cada archivo agrupa las pruebas de una función o característica.

# 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)
# })

Estructura de test_that()

test_that('description', { ... }) agrupa expectativas relacionadas. La cadena de descripción debe completar la oración «test that ...» y ser lo bastante específica para resultar útil en los mensajes de error.

# 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() y expect_identical()

expect_equal(actual, expected) realiza la comprobación con una tolerancia numérica para los números de coma flotante. expect_identical(actual, expected) requiere igualdad exacta, incluido el tipo. En la mayoría de los casos, es preferible expect_equal().

# 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() y expect_warning()

Compruebe que las funciones produzcan los errores y advertencias correctos. Pase un patrón de expresión regular para coincidir con el mensaje de error; así se asegura de que se produzca el error adecuado y no simplemente cualquier error.

# 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() y expect_false()

expect_true(expr) y expect_false(expr) comprueban condiciones lógicas. Utilícelas al probar predicados o condiciones que devuelvan un único valor lógico.

# 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)
# })

Más funciones de expectativa

testthat proporciona numerosas funciones de expectativa para distintos casos:

  • expect_length(x, n) — comprobar la longitud de un vector
  • expect_type(x, 'double') — comprobar el tipo base
  • expect_s3_class(x, 'data.frame') — comprobar la clase S3
  • expect_null(x) — comprobar si es NULL
  • expect_match(string, regexp) — comprobar el patrón de una cadena
# 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')
# })

Ejecutar pruebas con devtools::test()

devtools::test() (Ctrl+Shift+T) ejecuta todos los archivos de pruebas y muestra un resumen de pruebas superadas, fallos y advertencias. Los fallos individuales muestran la expectativa que no se cumplió y los valores real y esperado.

# 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 ]

Cobertura de pruebas con covr

covr::package_coverage() mide qué porcentaje de las líneas del paquete ejecutan las pruebas. covr::report() abre un informe HTML que muestra las líneas cubiertas (en verde) y no cubiertas (en rojo). Procure alcanzar al menos un 80 % de cobertura.

# 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

Probar casos límite

Las buenas pruebas cubren no solo el caso habitual, sino también los casos límite:

  • Entradas vacías: numeric(0), character(0)
  • Entradas NA: ¿la función propaga o gestiona NA?
  • Entradas de longitud 1 frente a entradas de longitud n
  • Valores límite: 0, números negativos y valores muy grandes
  • Tipos incorrectos: ¿qué ocurre cuando el usuario pasa una cadena a una función numérica?
# 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)
# })

Comprobación rápida: expect_error()

Ejecuta expect_error(my_fn('bad'), regexp = 'invalid input'). ¿Qué comprueba esta prueba?

Repaso de pruebas unitarias

Pruebas de un paquete de R con testthat:

  • usethis::use_testthat() — configura la infraestructura de pruebas una sola vez
  • usethis::use_test('fn') — crea tests/testthat/test-fn.R
  • test_that('description', {...}) — agrupa expectativas relacionadas
  • expect_equal(), expect_error(), expect_warning(), expect_true(), expect_false() — funciones principales de expectativas
  • devtools::test() — ejecuta todas las pruebas (Ctrl+Shift+T)
  • covr::package_coverage() — mide la cobertura de pruebas

Preguntas frecuentes

¿La lección «Pruebas unitarias con testthat» es gratis?

Sí — el texto completo de «Pruebas unitarias con testthat» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de R Academy, actualiza a CoddyKit PRO. El curso de R Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Pruebas unitarias con testthat»?

Escriba bloques test_that(), use expectations y ejecute pruebas con devtools::test(). Practicas R Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar R Academy?

No se requiere experiencia previa. R Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «Pruebas unitarias con testthat»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de R Academy?

Sí. Cada lección de R Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Estructura de paquetes con usethis y devtools
  2. Documentación de funciones con roxygen2
  3. Pruebas unitarias con testthat
  4. Envío a CRAN y mantenimiento de paquetes
← Volver a R Academy