0Pricing
R Academy · Aula

Testes unitários com testthat

Escreva blocos test_that(), use expectativas e execute testes com devtools::test().

Testes unitários com testthat é uma aula grátis de R Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de R Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de R Academy inclui 4 aulas no total.

Por que fazer testes unitários?

Os testes unitários verificam automaticamente se funções individuais se comportam corretamente. Eles detectam regressões quando você altera o código, servem como documentação executável e dão confiança para refatorar com segurança. O pacote testthat é a estrutura de testes padrão para pacotes R.

Configurando o testthat

usethis::use_testthat() adiciona testthat a Suggests em DESCRIPTION, cria tests/testthat/ e cria o script executor tests/testthat.R. Execute-o uma vez ao inicializar um pacote novo.

# 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

Criando um arquivo de testes

usethis::use_test('add') cria tests/testthat/test-add.R. Por convenção, os arquivos de testes recebem nomes como test-{function_name}.R. Cada arquivo reúne os testes de uma função ou funcionalidade.

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

Estrutura de test_that()

test_that('description', { ... }) agrupa expectativas relacionadas. A cadeia de caracteres de descrição deve completar a frase 'testar se ...' e ser específica o bastante para ser útil nas mensagens de falha.

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

expect_equal(actual, expected) testa com uma tolerância numérica para números de ponto flutuante. expect_identical(actual, expected) exige igualdade exata, inclusive quanto ao tipo. Na maioria dos casos, expect_equal() é preferível.

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

Verifique se as funções produzem os erros e avisos corretos. Passe um padrão de expressão regular para corresponder à mensagem de erro — isso garante que o erro correto seja gerado, e não apenas qualquer erro.

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

expect_true(expr) e expect_false(expr) testam condições lógicas. Use-as ao testar predicados ou condições que retornam um ú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)
# })

Mais funções de expectativa

testthat fornece muitas funções de expectativa para diferentes situações:

  • expect_length(x, n) — verificar o comprimento do vetor
  • expect_type(x, 'double') — verificar o tipo básico
  • expect_s3_class(x, 'data.frame') — verificar a classe S3
  • expect_null(x) — verificar se é NULL
  • expect_match(string, regexp) — verificar o padrão da cadeia de caracteres
# 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')
# })

Executando testes com devtools::test()

devtools::test() (Ctrl+Shift+T) executa todos os arquivos de testes e exibe um resumo dos sucessos, falhas e avisos. As falhas de testes individuais mostram a expectativa que falhou e os valores real e 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 testes com covr

covr::package_coverage() mede qual porcentagem das linhas do seu pacote é executada pelos testes. covr::report() abre um relatório HTML mostrando as linhas cobertas (em verde) e não cobertas (em vermelho). Procure obter pelo menos 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

Testando casos extremos

Bons testes abrangem não apenas o caminho esperado, mas também casos extremos:

  • Entradas vazias: numeric(0), character(0)
  • Entradas NA: a função propaga ou trata NA?
  • Entradas de comprimento 1 versus comprimento n
  • Valores-limite: 0, números negativos, valores muito grandes
  • Tipos incorretos: o que acontece quando o usuário passa uma cadeia de caracteres para uma função 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)
# })

Verificação rápida: expect_error()

Você chama expect_error(my_fn('bad'), regexp = 'invalid input'). O que esse teste verifica?

Recapitulação de testes unitários

Testando um pacote R com testthat:

  • usethis::use_testthat() — configura a infraestrutura de testes uma vez
  • usethis::use_test('fn') — cria tests/testthat/test-fn.R
  • test_that('description', {...}) — agrupa expectativas relacionadas
  • expect_equal(), expect_error(), expect_warning(), expect_true(), expect_false() — funções principais de expectativa
  • devtools::test() — executa todos os testes (Ctrl+Shift+T)
  • covr::package_coverage() — mede a cobertura dos testes

Perguntas Frequentes

A aula “Testes unitários com testthat” é grátis?

Sim — o texto completo de “Testes unitários com testthat” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de R Academy, atualize para CoddyKit PRO. O curso de R Academy inclui 4 aulas no total.

O que vou aprender em “Testes unitários com testthat”?

Escreva blocos test_that(), use expectativas e execute testes com devtools::test(). Você pratica R Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar R Academy?

Nenhuma experiência prévia é necessária. R Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “Testes unitários com testthat”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de R Academy?

Sim. Cada aula de R Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Estrutura de pacotes com usethis e devtools
  2. Documentando funções com roxygen2
  3. Testes unitários com testthat
  4. Submissão ao CRAN e manutenção de pacotes
← Voltar para R Academy