Batjocorește -le pe toate: simulați -vă la un test mai bun cu testthat

URMĂREȘTE-NE
16,065FaniÎmi place
1,142CititoriConectați-vă

(Acest articol a fost publicat pentru prima dată pe Rtaskși a contribuit cu drag la R-Bloggers). (Puteți raporta problema despre conținutul de pe această pagină aici)


Doriți să vă împărtășiți conținutul pe R-Bloggers? Faceți clic aici dacă aveți un blog sau aici dacă nu.

Puteți citi postarea originală în formatul său original pe site -ul RTASk de Thinkr aici: Mock -le toate: Simulați -vă pentru a testa mai bine cu Testthat

Testarea unităților în R. Știți, acele mici funcții care vă asigură că codul dvs. funcționează perfect – chiar și atunci când sunteți în vacanță sau scrieți noi module la 2 dimineața
Dar să fim sinceri: când vine vorba de testarea interacțiunilor utilizatorilor sau a resurselor externe, lucrurile se pot transforma rapid într -o durere de cap.
Ce faceți atunci când codul dvs. necesită un dialog de selecție a fișierelor sau o conexiune la o API care durează pentru totdeauna pentru a răspunde?
În niciun caz nu doriți să blocați totul doar pentru un test!

În aceste cazuri, este timpul să devii deștept. Ideea nu este de a renunța la testare, ci de a ocoli inteligent ceea ce este problematic. Acolo vine o tehnică cunoscută: mocking.
Din fericire, R și testthat Pachetul oferă instrumente doar pentru acest lucru.

Mocking înseamnă înlocuirea temporară a unei funcții sau a unei resurse cu o versiune falsă, controlată, care simulează comportamentul așteptat.

Intrigat? Să ne scufundăm.

Arta lui Pretending: Simularea interacțiunilor utilizatorului

Imaginează -ți o funcție care solicită utilizatorului să selecteze un fișier.
Dacă ar trebui să testați această funcție cu o casetă de dialog reală, ar fi o pierdere totală de timp – ca să nu menționați imposibil de automatizat cu ușurință într -un mediu CI.
Acolo este magia mocking intră.

Iată un exemplu al unei astfel de funcții:

select_file <- function() {
  file_path <- choose.files()  # Cette fonction ouvre une boîte de dialogue
  cat("You have chosen the file :", file_path)
}

Nu doriți să selectați manual un fișier de fiecare dată când executați testul.
Cu with_mocked_bindings() din {testthat} pachet, puteți înlocui choose.files cu o versiune care returnează pur și simplu o cale predefinită.
Acest lucru evită orice interacțiune și face testul instantaneu:

test_that("select_file works without a dialog box", {
  with_mocked_bindings(
    code = {
      expect_output(select_file(), "You have chosen the file : C:/fakedir/fakefile.txt")
    },
    choose.files = function() {"C:/fakedir/fakefile.txt"}
  )
})

Și asta este! Testați funcția ca și cum utilizatorul a selectat deja un fișier – nici o casetă de dialog implicată.

Când simularea devine esențială: testarea resurselor externe

Testele unitare sunt adesea utilizate pentru a verifica funcțiile care se bazează pe resurse externe, cum ar fi API -uri, baze de date sau interacțiuni de rețea.
Imaginează -ți o funcție care preia datele dintr -o API.
Apelarea API -ului în timpul fiecărui test ar fi lent, costisitor și complet inutil.
În schimb, puteți simula răspunsul API. Iată cum:

fetch_data <- function() {
  response <- httr::GET("https://api.exemple.com/data")
  content <- httr::content(response)
  return(content)
}

Pentru a testa această funcție fără a efectua un apel real API, puteți batjocori răspunsul folosind with_mocked_bindings.

Iată un exemplu în care apelul API este înlocuit cu un răspuns realizat manual:

Acum testezi funcția fără să lovești vreodată API -ul real și ai un control complet asupra a ceea ce a revenit.
Puteți simula diferite situații (răspuns de succes, eroare, timeout etc.) fără a depinde de starea API reală.

⚠️ Nu totul poate fi batjocorit: limitările

Unele funcții nu pot fi batjocorite direct, de exemplu:

Sys.time()
Sys.getenv()

Încercând să le înlocuiesc cu with_mocked_bindings() Rezultate în:

Error in `local_mocked_bindings(...)`: Can't find binding for `Sys.time`

De ce? Pentru că anumite funcții precum Sys.time() şi Sys.getenv() sunt funcții primitive în R.
Sunt profund încorporate în nucleul limbajului și nu sunt obiecte R obișnuite, puteți trece cu ușurință ca funcții definite de utilizator.

🩹 Soluția: încapsulează comportamentul

Soluția: creați o funcție de înveliș în codul dvs. mock.

Exemplu:

# Dans votre package
get_current_time <- function() { Sys.time()}
say_hello <- function() {
  if (format(get_current_time(), "%H") == "12") {
    "Time for lunch!"
  } else {
    "Just a little longer..."
  }
}

Testele ET DANS VOS:

test_that("say_hello correctly detects noon", {
  with_mocked_bindings(
    code = expect_equal(say_hello(), "Time for lunch!"),
    get_current_time = function() as.POSIXct("2025-04-25 12:00:00")
  )
})

🚪 În rezumat

  • with_mocked_bindings() Vă permite să simulați funcțiile al căror comportament variază în funcție de intrarea utilizatorului, de starea de sistem sau de timp, într -un mod elegant;
  • Unele funcții nu pot fi batjocorite direct (cum ar fi Sys.time, Sys.getenv): înfășurați -le într -o funcție separată;
  • Este o modalitate excelentă de a crea teste rapide, fiabile, non-interactive.

Această postare este mai bine prezentată pe site -ul său original Thinkr aici: batjocorește -le pe toate: Simulați -vă pentru a testa mai bine cu Testthat

Dominic Botezariu
Dominic Botezariuhttps://www.noobz.ro/
Creator de site și redactor-șef.

Cele mai noi știri

Pe același subiect

LĂSAȚI UN MESAJ

Vă rugăm să introduceți comentariul dvs.!
Introduceți aici numele dvs.