tests/testthat/test-traitement.R

# =============================================================================
# Tests unitaires — Module Traitement
# statAfrikR
# =============================================================================

# Données de test partagées
set.seed(123)
donnees_test <- tibble::tibble(
  id      = 1:100,
  age     = c(sample(c(10,15,20,25,30,35,40,45,50,55,60), 80, replace = TRUE),
              rep(NA, 20)),
  sexe    = sample(c("Masculin", "Féminin"), 100, replace = TRUE),
  region  = sample(c("Nord", "Sud", "Est", "Ouest", "Centre"), 100, replace = TRUE),
  revenu  = c(abs(rnorm(85, 150000, 80000)), rep(NA, 15)),
  poids   = runif(100, 0.5, 2.5),
  strate  = sample(c("Urbain", "Rural"), 100, replace = TRUE),
  grappe  = sample(1:20, 100, replace = TRUE)
)

# --- nettoyer_libelles -------------------------------------------------------

test_that("nettoyer_libelles() retourne un tibble de même dimension", {
  result <- nettoyer_libelles(donnees_test, vars = "region")
  expect_s3_class(result, "tbl_df")
  expect_equal(dim(result), dim(donnees_test))
})

test_that("nettoyer_libelles() supprime les espaces superflus", {
  df <- tibble::tibble(region = c("  Nord  ", " Sud", "Est   "))
  result <- nettoyer_libelles(df, vars = "region", casse = "aucune")
  expect_equal(result$region, c("Nord", "Sud", "Est"))
})

test_that("nettoyer_libelles() applique la casse majuscule", {
  df <- tibble::tibble(region = c("nord", "sud", "est"))
  result <- nettoyer_libelles(df, vars = "region", casse = "majuscule")
  expect_equal(result$region, c("NORD", "SUD", "EST"))
})

test_that("nettoyer_libelles() applique la casse minuscule", {
  df <- tibble::tibble(region = c("NORD", "SUD"))
  result <- nettoyer_libelles(df, vars = "region", casse = "minuscule")
  expect_equal(result$region, c("nord", "sud"))
})

test_that("nettoyer_libelles() préserve les accents", {
  df <- tibble::tibble(region = c("  SÉNÉGAL  ", "côte d'ivoire"))
  result <- nettoyer_libelles(df, vars = "region", casse = "titre")
  expect_true(any(grepl("Sénégal", result$region)))
})

test_that("nettoyer_libelles() traite toutes les vars character si vars = NULL", {
  result <- nettoyer_libelles(donnees_test)
  expect_s3_class(result, "tbl_df")
})

test_that("nettoyer_libelles() échoue sur variable inexistante", {
  expect_error(
    nettoyer_libelles(donnees_test, vars = "variable_inexistante"),
    regexp = "introuvable"
  )
})

test_that("nettoyer_libelles() échoue si data n'est pas un data.frame", {
  expect_error(nettoyer_libelles("pas_un_df"), regexp = "data.frame")
})

# --- harmoniser_regions ------------------------------------------------------

test_that("harmoniser_regions() ajoute une colonne region_std", {
  result <- harmoniser_regions(donnees_test, "region")
  expect_true("region_std" %in% names(result))
})

test_that("harmoniser_regions() utilise le référentiel pays BJ", {
  df <- tibble::tibble(region = c("alibori", "Atacora", "ATLANTIQUE"))
  result <- harmoniser_regions(df, "region", pays = "BJ",
                                signaler_non_trouves = FALSE)
  expect_true("region_std" %in% names(result))
})

test_that("harmoniser_regions() utilise une table de correspondance manuelle", {
  table_corr <- data.frame(
    original    = c("nord", "sud", "est", "ouest", "centre"),
    standardise = c("Nord", "Sud", "Est", "Ouest", "Centre")
  )
  df <- tibble::tibble(region = c("nord", "sud", "est"))
  result <- harmoniser_regions(df, "region",
                                table_correspondance = table_corr,
                                signaler_non_trouves = FALSE)
  expect_equal(result$region_std, c("Nord", "Sud", "Est"))
})

test_that("harmoniser_regions() échoue sur variable inexistante", {
  expect_error(
    harmoniser_regions(donnees_test, "var_inexistante"),
    regexp = "introuvable"
  )
})

test_that("harmoniser_regions() utilise var_sortie personnalisée", {
  result <- harmoniser_regions(donnees_test, "region",
                                var_sortie = "ma_region_std")
  expect_true("ma_region_std" %in% names(result))
})

# --- appliquer_ponderations --------------------------------------------------

test_that("appliquer_ponderations() retourne un objet svydesign", {
  skip_if_not_installed("survey")
  result <- appliquer_ponderations(donnees_test, "poids")
  expect_s3_class(result, "survey.design")
})

test_that("appliquer_ponderations() fonctionne avec strate et grappe", {
  skip_if_not_installed("survey")
  result <- appliquer_ponderations(
    donnees_test, "poids",
    var_strate = "strate",
    var_grappe = "grappe"
  )
  expect_s3_class(result, "survey.design")
})

test_that("appliquer_ponderations() échoue sur poids négatifs", {
  df_pb <- donnees_test
  df_pb$poids[1] <- -1
  expect_error(
    appliquer_ponderations(df_pb, "poids"),
    regexp = "négatif"
  )
})

test_that("appliquer_ponderations() échoue sur poids nuls", {
  df_pb <- donnees_test
  df_pb$poids[1] <- 0
  expect_error(
    appliquer_ponderations(df_pb, "poids"),
    regexp = "nul"
  )
})

test_that("appliquer_ponderations() avertit sur poids NA", {
  df_na <- donnees_test
  df_na$poids[1:5] <- NA
  expect_warning(
    appliquer_ponderations(df_na, "poids"),
    regexp = "manquante"
  )
})

test_that("appliquer_ponderations() échoue sur variable de poids inexistante", {
  expect_error(
    appliquer_ponderations(donnees_test, "poids_inexistant"),
    regexp = "introuvable"
  )
})

test_that("appliquer_ponderations() normalise les poids si demandé", {
  skip_if_not_installed("survey")
  result <- appliquer_ponderations(donnees_test, "poids", normaliser = TRUE)
  expect_s3_class(result, "survey.design")
})

# --- imputer_valeurs ---------------------------------------------------------

test_that("imputer_valeurs() réduit les NA avec méthode médiane", {
  result <- imputer_valeurs(donnees_test, vars = "age",
                             methode = "mediane", rapport = FALSE)
  expect_equal(sum(is.na(result$age)), 0)
})

test_that("imputer_valeurs() réduit les NA avec méthode moyenne", {
  result <- imputer_valeurs(donnees_test, vars = "revenu",
                             methode = "moyenne", rapport = FALSE)
  expect_equal(sum(is.na(result$revenu)), 0)
})

test_that("imputer_valeurs() réduit les NA avec méthode mode", {
  result <- imputer_valeurs(donnees_test, vars = "sexe",
                             methode = "mode", rapport = FALSE)
  expect_equal(sum(is.na(result$sexe)), 0)
})

test_that("imputer_valeurs() réduit les NA avec hot_deck", {
  result <- imputer_valeurs(donnees_test, vars = "age",
                             methode = "hot_deck", rapport = FALSE)
  expect_equal(sum(is.na(result$age)), 0)
})

test_that("imputer_valeurs() retourne une liste si rapport = TRUE", {
  result <- imputer_valeurs(donnees_test, vars = "age",
                             methode = "mediane", rapport = TRUE)
  expect_type(result, "list")
  expect_true("donnees" %in% names(result))
  expect_true("rapport" %in% names(result))
})

test_that("imputer_valeurs() retourne un tibble si rapport = FALSE", {
  result <- imputer_valeurs(donnees_test, vars = "age",
                             methode = "mediane", rapport = FALSE)
  expect_s3_class(result, "tbl_df")
})

test_that("imputer_valeurs() échoue sur regression sans vars_auxiliaires", {
  expect_error(
    imputer_valeurs(donnees_test, vars = "age", methode = "regression"),
    regexp = "auxiliaires"
  )
})

test_that("imputer_valeurs() fonctionne avec regression et vars_auxiliaires", {
  result <- imputer_valeurs(
    donnees_test, vars = "age",
    methode = "regression",
    vars_auxiliaires = c("revenu", "poids"),
    rapport = FALSE
  )
  expect_s3_class(result, "tbl_df")
})

test_that("imputer_valeurs() message si aucune valeur manquante", {
  df_complet <- donnees_test[, c("id", "sexe", "region")]
  expect_message(
    imputer_valeurs(df_complet, methode = "mediane"),
    regexp = "manquante"
  )
})

# --- supprimer_doublons ------------------------------------------------------

test_that("supprimer_doublons() supprime les doublons exacts", {
  df_doublons <- dplyr::bind_rows(donnees_test, donnees_test[1:10, ])
  result <- supprimer_doublons(df_doublons, cles = "id", rapport = FALSE)
  expect_equal(nrow(result), nrow(donnees_test))
})

test_that("supprimer_doublons() retourne une liste si rapport = TRUE", {
  df_doublons <- dplyr::bind_rows(donnees_test, donnees_test[1:5, ])
  result <- supprimer_doublons(df_doublons, cles = "id", rapport = TRUE)
  expect_type(result, "list")
  expect_true("donnees" %in% names(result))
  expect_true("rapport" %in% names(result))
})

test_that("supprimer_doublons() garde le premier par défaut", {
  df_doublons <- dplyr::bind_rows(donnees_test, donnees_test[1:3, ])
  result <- supprimer_doublons(df_doublons, cles = "id",
                                garder = "premier", rapport = FALSE)
  expect_equal(nrow(result), nrow(donnees_test))
})

test_that("supprimer_doublons() message si aucun doublon", {
  expect_message(
    supprimer_doublons(donnees_test, cles = "id"),
    regexp = "doublon"
  )
})

test_that("supprimer_doublons() échoue sur clé inexistante", {
  expect_error(
    supprimer_doublons(donnees_test, cles = "cle_inexistante"),
    regexp = "introuvable"
  )
})

# --- recoder_variable --------------------------------------------------------

test_that("recoder_variable() recode correctement avec data.frame", {
  table_rec <- data.frame(
    avant = c("Masculin", "Féminin"),
    apres = c("M", "F")
  )
  result <- recoder_variable(donnees_test, "sexe", table_rec)
  expect_true(all(result$sexe %in% c("M", "F", NA)))
})

test_that("recoder_variable() fonctionne avec vecteur nommé", {
  result <- recoder_variable(
    donnees_test, "strate",
    table_recodage = c("Urbain" = "U", "Rural" = "R")
  )
  expect_true(all(result$strate %in% c("U", "R", NA)))
})

test_that("recoder_variable() crée une nouvelle colonne si var_sortie spécifié", {
  table_rec <- data.frame(avant = c("Masculin", "Féminin"),
                           apres = c("M", "F"))
  result <- recoder_variable(donnees_test, "sexe", table_rec,
                              var_sortie = "sexe_code")
  expect_true("sexe_code" %in% names(result))
  expect_true("sexe" %in% names(result))
})

test_that("recoder_variable() échoue sur variable inexistante", {
  table_rec <- data.frame(avant = "a", apres = "b")
  expect_error(
    recoder_variable(donnees_test, "var_inexistante", table_rec),
    regexp = "introuvable"
  )
})

# --- standardiser_ages -------------------------------------------------------

test_that("standardiser_ages() retourne une liste avec les indices", {
  result <- standardiser_ages(donnees_test, "age")
  expect_type(result, "list")
  expect_true("indice_whipple" %in% names(result))
  expect_true("indice_myers" %in% names(result))
  expect_true("diagnostic" %in% names(result))
})

test_that("standardiser_ages() retourne l'indice de Whipple entre 0 et 5", {
  result <- standardiser_ages(donnees_test, "age")
  if (!is.na(result$indice_whipple)) {
    expect_gte(result$indice_whipple, 0)
    expect_lte(result$indice_whipple, 5)
  }
})

test_that("standardiser_ages() échoue sur variable non numérique", {
  expect_error(
    standardiser_ages(donnees_test, "sexe"),
    regexp = "numérique"
  )
})

# --- fusion_datasets ---------------------------------------------------------

test_that("fusion_datasets() empile correctement (vertical)", {
  result <- fusion_datasets(
    list(a = donnees_test[1:50,], b = donnees_test[51:100,]),
    type = "vertical"
  )
  expect_equal(nrow(result), 100)
})

test_that("fusion_datasets() fusionne horizontalement (gauche)", {
  df1 <- donnees_test[, c("id", "age", "sexe")]
  df2 <- donnees_test[, c("id", "region", "revenu")]
  result <- fusion_datasets(
    list(df1 = df1, df2 = df2),
    type = "horizontal", cle = "id"
  )
  expect_equal(nrow(result), 100)
  expect_true(all(c("age", "region") %in% names(result)))
})

test_that("fusion_datasets() échoue si moins de 2 datasets", {
  expect_error(
    fusion_datasets(list(a = donnees_test)),
    regexp = "au moins 2"
  )
})

test_that("fusion_datasets() échoue si cle absente pour fusion horizontale", {
  expect_error(
    fusion_datasets(list(a = donnees_test, b = donnees_test),
                    type = "horizontal"),
    regexp = "clé"
  )
})

# --- tracer_flux_traitement --------------------------------------------------

test_that("tracer_flux_traitement() retourne une liste avec donnees et journal", {
  result <- tracer_flux_traitement(donnees_test, "Import initial")
  expect_type(result, "list")
  expect_true("donnees" %in% names(result))
  expect_true("journal" %in% names(result))
})

test_that("tracer_flux_traitement() cumule les entrées du journal", {
  etape1 <- tracer_flux_traitement(donnees_test, "Étape 1")
  etape2 <- tracer_flux_traitement(donnees_test, "Étape 2",
                                    journal = etape1$journal)
  expect_equal(nrow(etape2$journal), 2)
})

test_that("tracer_flux_traitement() contient les bonnes colonnes", {
  result <- tracer_flux_traitement(donnees_test, "Test")
  cols_attendues <- c("horodatage", "action", "n_lignes", "n_colonnes")
  expect_true(all(cols_attendues %in% names(result$journal)))
})

test_that("tracer_flux_traitement() échoue si action manquante", {
  expect_error(
    tracer_flux_traitement(donnees_test, ""),
    regexp = "obligatoire"
  )
})

Try the statAfrikR package in your browser

Any scripts or data that you put into this service are public.

statAfrikR documentation built on Sept. 20, 2026, 5:07 p.m.