(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 către Thinkr aici: De la laborator la viața reală: Cum poate supraviețui aplicația dvs. strălucitoare utilizatorii săi
De la prototip la producție, asigurați -vă că nimic nu se rupe …
Ai creat o machetă fantastică, iar clientul tău este încântat. Sunteți gata să treceți la producție cu aplicația dvs. Dar o întrebare te bântuie: cum te poți asigura că aplicația dvs. va rămâne stabilă și funcțională prin modificări și evoluții?
Răspunsul se reduce la un singur cuvânt: testare.
În urmă cu trei săptămâni, o parte a echipei Thinkr a fost în Belgia pentru a participa la Rencontres r 2025. O conferință în jurul lui R al cărei obiectiv este de a oferi comunității de limbă franceză un loc pentru schimb și împărtășirea ideilor privind utilizarea The the R limbaj pe toate disciplinele.
Marți după-amiază, în timpul unei prezentări de 15 minute, am prezentat utilizarea testării într-o aplicație strălucitoare (prezentare disponibilă în engleză și franceză). După câteva ore de pregătire și prezentare, mintea mea era atunci orientat către test. La sfârșitul conferinței de 3 zile, m-am îngăduit în cel de-al doilea hobby (după dezvoltarea R): alergare. În timp ce alergam, o melodie cânta în urechile mele: Să vorbim despre sex de sare-n-pepa. Nu puteam auzi decât: „Să vorbim despre tine și despre mine (…) să vorbim despre teste”. Prejudecată profesională? Cu siguranţă.
Muzică la volum complet, să vorbim despre teste!
Eu, nu cred că ar trebui să vorbim despre asta
Haide, de ce nu?
Oamenii ar putea înțelege greșit ceea ce încercăm să spunem, știi?
Nu, dar asta este o parte a vieții
(…)
Să vorbim despre (teste), iubito
https://www.youtube.com/watch?v=ydrtf45-yg
Prea des neglijată în ecosistemul R, testele sunt totuși esențiale pentru garantarea robustetei și durabilității aplicațiilor tale strălucitoare. În acest articol, vom explora o strategie de testare pe trei niveluri care vă va permite să vă asigurați codul de la dezvoltare la producție.
De ce să -ți testezi aplicațiile strălucitoare?
Dezvoltarea unei aplicații strălucitoare urmează adesea aceeași cale: începeți cu un prototip rapid, iterați cu clientul (sau dvs.), adăugați funcții … și dintr -o dată, vă dați seama că codul dvs. a devenit complex și fragil.
Fiecare nouă modificare riscă să rupă o funcționalitate existentă. Fiecare adăugare a caracteristicilor te face să te temi de introducerea regresiei. Aici testele devin cel mai bun aliat.
Avantajele unei strategii de testare
O strategie de testare bine gândită vă permite:
- Validați progresiv codul dvs. la fiecare etapă de dezvoltare
- Detectează regresii Înainte de a ajunge la utilizatorii dvs.
- Refactor cu liniște sufletească Știind că testele dvs. vă vor avertiza în caz de probleme
- Documentați comportamentul așteptat a aplicației dvs.
- Facilitarea întreținerii și evoluții viitoare
Prezentare generală
Pentru a asigura eficient o aplicație strălucitoare, vă recomandăm o abordare pe trei niveluri:
- Testele unitare: Validați fiecare funcție individual
- Teste de integrare: Verificați interacțiunile dintre componente
- Teste end-to-end: Simulați un utilizator real într -un browser real
Fiecare nivel are rolul și specificitățile sale. Împreună, ele formează o plasă de siguranță completă pentru aplicația dvs.
Nivelul 1: Testele unitare
Principiul
Testele unitare constau în testarea fiecărei funcții în mod izolat, independent de restul aplicației.
Este ca și cum ai verifica dacă un sertar se deschide corect înainte de a -l instala într -o bucătărie.
Implementare
Dacă urmați cele mai bune practici și vă dezvoltați aplicația strălucitoare ca pachet (cu {golem}
), testele unitare se integrează în mod natural în fluxul de lucru.
Să creăm prima noastră aplicație:
# install.packages("golem") golem::create_golem(path = "myShinyApp")
Odată ce acest cod va fi executat, pachetul dvs. se va deschide într -o nouă sesiune. Puteți verifica imediat dacă aplicația dvs. se lansează corect:
# Launch application in dev mode golem::run_dev()
În {golem}
ciclul de dezvoltare se găsește în /dev
pliant. Veți găsi toate funcțiile de care aveți nevoie pentru dezvoltare acolo.
Primul fișier de urmat este dev/01_start.R
fişier. Conține toate funcțiile de care aveți nevoie pentru a începe proiectul. Printre ele se numără funcția: golem::use_recommended_tests()
. Această funcție va crea structura de testare în pachetul dvs., cu teste recomandate de {golem}
inclusiv una care verifică dacă aplicația dvs. se va lansa corect. Convenabil!
Să ne imaginăm că avem nevoie de o funcție în aplicația noastră: calculate_average()
. Putem executa: usethis::use_r("calculate_average")
Pentru a crea fișierul care va conține funcția noastră.
# In R/calculate_average.R calculate_average <- function(values) { if (!is.numeric(values)) { stop("values must be numeric") } if (length(values) == 0) { return(0) } sum(values) / length(values) }
Această funcție calculează în medie. Are unii „validatori” pentru a verifica intrările funcției. Pentru a asocia un test de unitate cu acesta, putem executa: usethis::use_test(name = "calculate_average")
# In tests/testthat/test-calculate_average.R test_that("calculate_average works correctly", { # Test with numeric values expect_equal( object = calculate_average( values = c(10, 20, 30) ), expected = 20 ) # Test with empty vector expect_equal( object = calculate_average( values = 0 ), expected = 0 ) # Test with non-numeric input expect_error( object = calculate_average( values = c("a", "b") ), "values must be numeric" ) })
Pentru a verifica dacă calculate_average
Funcția funcționează așa cum era de așteptat, rulăm testele:
devtools::test()
Dacă testele au succes, obținem:
Puteți modifica/rupe un test pentru a vedea și experimenta cu un test care nu reușește!
Înlocuicalculate_average(values = c(10, 20, 30))
cucalculate_average(values = c(10, 20, 1))
pentru a vedea rezultatul.
În această etapă, testele unitare ne permit să testăm funcțiile de afaceri ale aplicației noastre. Nu testăm aplicația în sine, dar asigurăm un comportament bun al logicii sale de afaceri.
Nivelul 2: Teste de integrare
Principiul
Testele de integrare verifică dacă diferitele componente ale aplicației dvs. funcționează corect împreună. În strălucire, aceasta înseamnă testarea fluxurilor reactive, interacțiunilor dintre module și logica serverului.
Am verificat dacă sertarul s -ar putea deschide corect. Acum vom verifica dacă se integrează corect cu restul mobilierului de bucătărie: celelalte sertare, blatul de lucru, etc …
Implementare
Să modificăm puțin aplicația noastră!
În R/app_ui.R
fișier, înlocuiți golem::golem_welcome_page()
Funcție cu următorul cod:
numericInput(inputId = "num1", label = "First value", value = 10), numericInput(inputId = "num2", label = "Second value", value = 10), numericInput(inputId = "num3", label = "Third value", value = 10), numericInput(inputId = "num4", label = "Fourth value", value = 10), actionButton(inputId = "go", label = "Calculate!"), textOutput(outputId = "result")
Acest lucru ar trebui să dea:
app_ui <- function(request) { tagList( golem_add_external_resources(), fluidPage( numericInput(inputId = "num1", label = "First value", value = 10), numericInput(inputId = "num2", label = "Second value", value = 10), numericInput(inputId = "num3", label = "Third value", value = 10), numericInput(inputId = "num4", label = "Fourth value", value = 10), actionButton(inputId = "go", label = "Calculate!"), textOutput(outputId = "result") ) ) }
Tocmai am adăugat 5 intrări, inclusiv 4 intrări pentru a introduce o valoare numerică și un buton de acțiune. În cele din urmă, a textOutput
ne va permite să afișăm text.
Aveți grijă să puneți o virgulă între diferitele elemente ale UI.
Pentru a verifica dacă funcționează acest cod, putem lansa aplicația:
# Launch application in dev mode golem::run_dev()
Este timpul să conectăm partea UI a aplicației noastre cu partea serverului. Pentru asta, în R/app_server.R
:
app_server <- function(input, output, session) { rv <- reactiveValues() observeEvent(input$go, { rv$avg <- calculate_average( c(input$num1, input$num2, input$num3, input$num4) ) showNotification( "Calculation completed!", duration = 3 ) }) output$result <- renderText({ req(rv$avg) paste("Average:", rv$avg) }) }
Acest cod a creat doar un reactiveValues()
o cutie care va stoca diferitele rezultate în aplicația noastră. Când este clic pe butonul, codul din interiorul observeEvent
va fi executat. Depozităm rezultatul nostru calculate_average
Funcție în reactiveValues
.
# Launch application in dev mode golem::run_dev()
Funcția TestServer ()
Shiny oferă testServer()
Funcție care permite logica serverului de testare fără a lansa interfața de utilizator.
Într -un fișier nou usethis::use_test(name = "server")
copiați următorul cod:
testServer(app_server, { session$setInputs(num1 = 5) session$setInputs(num2 = 5) session$setInputs(num3 = 5) session$setInputs(num4 = 5) session$setInputs(go = 1) expect_equal( object = rv$avg, expected = 5 ) session$setInputs(num1 = 10) session$setInputs(num2 = 20) session$setInputs(num3 = 30) session$setInputs(num4 = 12) session$setInputs(go = 2) expect_equal( object = rv$avg, expected = 18 ) })
Acest test simulează valorile pentru diferitele intrări din server și simulează, de asemenea, un clic pe buton session$setInputs(go = 1)
.
Ne așteptăm apoi la rezultatul stocat în reactiveValues
a fi 5:
expect_equal( object = rv$avg, expected = 5 )
Ca și înainte, pentru a rula testele în aplicația noastră, executăm:
devtools::test()
Puteți rupe întotdeauna un test pentru a experimenta cu un test eșuat!
Înlocuisession$setInputs(num3 = 30)
cusession$setInputs(num3 = 2)
pentru a vedea rezultatul.
Această logică de testare a integrării cu testServer
Poate fi folosit și cu module în strălucire! Prin urmare, pot fi testate aplicații complete și mai complexe.
Tocmai am testat interacțiunile cuibărite în aplicație și în special în diferite interacțiuni. Totuși, acest lucru rămâne foarte „programatic”Și nu reflectă experiența reală a unui utilizator într -un browser.
Nivelul 3: Teste end-to-end
Principiul
Testele end-to-end simulează un utilizator real care interacționează cu aplicația dvs. într-un browser real. Acesta este nivelul de testare cel mai apropiat de experiența finală a utilizatorului.
Obiectivele sunt multiple aici:
- Simulați interacțiunile reale ale utilizatorilor
- Testați aplicația într -un browser real
- Verificați experiența completă a utilizatorului
Am verificat sertarele individual. De asemenea, am verificat că toate ar putea fi asamblate împreună. Acum, este timpul să testați gătitul unei adevărate mese în bucătărie!
Dramaturg și The {pw}
pachet
Pentru testele E2E (end-to-end) în ecosistemul R, vă recomandăm să utilizați Dramaturg prin {pw}
Pachet dezvoltat de Thinkr.
Instalare și configurare:
# Package installation (in development) devtools::install_github("ThinkR-open/pw") # Initialize test structure pw::pw_init()
Această comandă creează următoarea structură:
tests/ ├── playwright/ ├── tests/ ├── default.test.ts └── testthat/ ├── test-calculate_average.R ├── test-golem-recommended.R ├── test-server.R └── test-playwright.R
Testele E2E trebuie plasate în playwright/tests/
pliant. Un test este deja disponibil, acesta conține:
import { test, expect } from '@playwright/test'; test('has body', async ({ page }) => { await page.goto('http://127.0.0.1:3000'); await expect(page.locator('body')).toBeVisible(); });
Acest cod va lansa aplicația într -un browser și va verifica prezența noastră body
. Putem rula deja acest test:
pw::pw_test()
Dramaturg De asemenea, oferă un raport pe care îl putem consulta:
pw::pw_show_report()
Dramaturg rulează acest test în 3 browsere diferite: chromium
, firefox
şi webkit
.
OK, dar cum ne testăm aplicația?
Vești bune, nu trebuie neapărat să înveți TypeScript
pentru a produce teste E2E cu Dramaturg:
pw::pw_codegen()
Această funcție va deschide un browser, în care vom putea simula clicuri și acțiuni, ca utilizator.
Dramaturg ne vom înregistra acțiunile și le va stoca într -un fișier nou în tests/playwright/tests
:
import { test, expect } from '@playwright/test'; test('test', async ({ page }) => { await page.goto('http://localhost:3000/'); await page.getByRole('spinbutton', { name: 'First value' }).click(); await page.getByRole('spinbutton', { name: 'First value' }).fill('20'); await page.getByText('First value Second').click(); await page.getByRole('button', { name: 'Calculate!' }).click(); await page.getByText('Average:').click(); });
Acest test este departe de a fi perfect și ne vom întoarce într -un articol viitor la sintaxa testelor cu Dramaturg Și cum să le optimizați. Testele E2E funcționează și în CI și vom reveni și la acest articol.
Între timp, aplicația noastră aici este testată într -un context care se apropie cel mai mult de realitatea viitorilor noștri utilizatori. Tocmai am asigurat funcționarea corectă a aplicației, atât pe logica de afaceri, cât și pe partea UI.
Putem rula toate testele din aplicația noastră:
devtools::test()
Strategia de testare recomandată
Distribuția efortului
O regulă acceptată frecvent în industrie este Piramida de testare:
- 70% teste unitare: Rapid, de încredere, numeroase
- 20% teste de integrare: Concentrați -vă pe interacțiuni critice
- 10% teste E2E: Călătorii esențiale pentru utilizatori
Ce să testați la fiecare nivel?
Teste unitare:
- Toate funcțiile de utilitate și logică de afaceri
- Funcții de transformare a datelor
- Algoritmi de calcul
- Funcții de validare a intrării
Teste de integrare:
- Principalele fluxuri reactive ale aplicației
- Interacțiuni între module strălucitoare
- Logică complexă a serverului
- Actualizări valorile reactive
Teste end-to-end:
- Călătorii critice ale utilizatorului
- Fluxuri de lucru complete (autentificare, calcul, export)
- Caracteristici complexe care implică mai multe interacțiuni
- Teste de regresie pe bug -uri majore
Concluzie
Implementarea unei strategii de testare pe trei niveluri transformă radical modul în care vă dezvoltați și vă mențineți aplicațiile strălucitoare.
Beneficii concrete:
- Încredere în codul și modificările dvs.
- Viteză de detectare a problemelor
- Uşura de întreținere și evoluție
- Îmbunătățit Calitatea utilizatorului
Pentru a începe astăzi:
- Structurați -vă aplicația strălucitoare ca pachet cu
{golem}
- Adăugați teste unitare pentru funcțiile dvs. critice
- Implementați unele teste de integrare cu
testServer()
- Experimentați cu teste E2E prin intermediul
{pw}
pentru călătoriile principale ale utilizatorului
Nu ezitați să ne contactați dacă doriți să aprofundați implementarea testelor în aplicațiile dvs. strălucitoare!
Puteți găsi, de asemenea, Colin Fay, care va conduce un atelier miercuri, 8 octombrie 2025 în timpul conferinței de producție strălucitoare organizată de Jumping Rivers.
Puteți găsi, de asemenea, toate cursurile noastre de formare pe dezvoltarea de aplicații strălucitoare aici!
Această postare este mai bine prezentată pe site -ul său original Thinkr aici: de la laborator la viața reală: Cum poate supraviețui aplicația dvs. strălucitoare pe utilizatorii săi