CineBase ha 639 test backend (xUnit) e ~160 test frontend (Playwright) per un totale di circa 800 test automatici. I test coprono tre livelli:
| Livello | Tecnologia | Cosa testa | Tempo esecuzione |
|---|---|---|---|
| Unit test backend | xUnit + EF Core InMemory | Logica di business pura | <1 minuto |
| Integration test backend | xUnit + SQLite in-memory + CustomWebApplicationFactory |
Pipeline ASP.NET completa, endpoint, DB, servizi fittizi | ~60 secondi |
| Browser audit frontend | Playwright (Chromium/Edge) | Render frontend con API mockate via page.route() |
~2 minuti |
| E2E smoke Docker | Playwright (container) + stack reale | Stack completo Docker con richieste HTTP reali | ~3 minuti |
Testano la logica di business senza la pipeline ASP.NET, usando database EF Core InMemory (creato per-test con GUID univoco) o nessun database.
Verificare il comportamento dei servizi di dominio in isolamento: CRUD, validazione input, configurazione SMTP.
| File | Classe | Cosa testa | DB |
|---|---|---|---|
FilmServiceTests.cs |
FilmServiceTests |
CRUD film: creazione, lettura, modifica, cancellazione, ricerca per id, input non valido | EF Core InMemory |
RegistaServiceTests.cs |
RegistaServiceTests |
CRUD registi: creazione, lettura, modifica, cancellazione, input non valido, film per regista | EF Core InMemory |
CinemaServiceTests.cs |
CinemaServiceTests |
CRUD cinema: creazione, lettura, modifica, cancellazione | EF Core InMemory |
BigliettoServiceTests.cs |
BigliettoServiceTests |
Metodo ResolveValidationBaseUrl(): URL assoluto (passthrough), URL relativo (normalizzazione), frontend mancante (fallback localhost) |
Nessuno |
SmtpDeliverySettingsTests.cs |
SmtpDeliverySettingsTests |
Caricamento configurazione SMTP da variabili d'ambiente: autenticazione vs no-auth, rilevamento Mailpit, default TLS. Include helper privato EnvironmentVariableScope per salvare/ripristinare env vars tra i test. |
Nessuno |
# Tutti i test backend (unit + integration)
dotnet test tests/backend/FilmAPI.Tests.csproj
# Solo unit test
dotnet test tests/backend/FilmAPI.Tests.csproj --filter "FullyQualifiedName~Unit"- Nessun server web: il
DbContextè creato conUseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()), garantendo isolamento completo tra test. - Parametrizer: i servizi vengono istanziati direttamente nei test passando il
DbContext. - Assertion: FluentAssertions (
Should().NotBeNull(),Should().BeEquivalentTo(), etc.).
Testano l'intera pipeline ASP.NET Core con un database SQLite in-memory, servizi fittizi (Stripe, email, OAuth, TMDB), e autenticazione simulata. Sono il grosso della suite (30+ classi di test).
Verificare che gli endpoint HTTP funzionino correttamente end-to-end: routing, autenticazione, autorizzazione, validazione input, logica di business, persistenza, risposte HTTP, header, cookie.
CustomWebApplicationFactory : WebApplicationFactory<FilmDbContext>, IAsyncLifetime
È il cuore di tutti i test di integrazione. Caratteristiche principali:
- Database: SQLite in-memory (
SqliteConnectionconDataSource=:memory:, aperto inInitializeAsynce chiuso inDisposeAsync). Ogni factory ha la propria connessione indipendente. - Fakes (sostituiscono i servizi reali):
FakeStripePaymentGateway— simula l'intera API Stripe: payment intent, checkout session, refund, firma webhook.FakeEmailService— cattura le email inviate (biglietti, cancellazione show). SupportaForceFailureper testare scenari di errore.FakeAccountEmailService— cattura le email di account (verifica, reset password, invito admin, cambio password, cancellazione account).FakeExternalAuthProvider(Google e Microsoft) — simula il flusso OAuth: state, code exchange, info utente.FakeTmdbImportService— restituisce risultati TMDB fittizi (Fight Club, Pulp Fiction, The Dark Knight).
- Autenticazione simulata:
TestAuthHandlerlegge header HTTP custom:X-Test-Role— ruolo (Admin, PowerUser, CinemaStaff, User)X-Test-UserId— ID utenteX-Test-Email— emailX-Test-Nome— nome
- HttpClient factory:
CreateAdminClient(userId)— client autenticato come AdminCreatePowerUserClient(userId)— PowerUserCreateCinemaStaffClient(userId)— CinemaStaffCreateUserClient(userId)— UserCreateAnonymousClient()— nessuna autenticazioneCreateAuthenticatedClient(role, userId, email, nome)— generico
- API path canonical handler:
CanonicalApiPathPrefixHandler(unDelegatingHandler) riscrive automaticamente i path canonici (es./films→/api/films) per 17 root path API. - Cookie container:
CookieContainerHandler(unDelegatingHandler) persiste i cookie tra richieste consecutive (fondamentale per testare il flusso refresh token viacinebase_refresh). - Reset database:
ResetDatabaseAsync(seed?)cancella e ricrea il DB, resetta tutti i fake, opzionalmente esegue una funzione di seed. - Configurazione:
ConfigureAppConfigurationconAddInMemoryCollectionper impostare limiti rate limiter altissimi (10000/1s), disabilitando di fatto il rate limiting nei test standard. - Classe non-sealed: permette ereditarietà per factory derivate come
TightRateLimitWebApplicationFactory.
Factory derivata in RateLimiterIntegrationTests.cs che sovrascrive i limiti del rate limiter in-memory:
config.AddInMemoryCollection(new Dictionary<string, string?>
{
["LOGIN_RATE_LIMIT_PERMITS"] = "6",
["LOGIN_RATE_LIMIT_WINDOW_SECONDS"] = "60",
["FORGOT_PASSWORD_RATE_LIMIT_PERMITS"] = "3",
["FORGOT_PASSWORD_RATE_LIMIT_WINDOW_SECONDS"] = "60",
});Usa builder.Configuration (non Environment.SetEnvironmentVariable) per evitare interferenze con altri test in esecuzione parallela.
| # | Classe | Cosa testa |
|---|---|---|
| 1 | ApiIntegrationTests |
CRUD registi, film, cinema, upload cover media, paginazione, ricerca, validazione, payload array legacy |
| 2 | AuthIntegrationTests |
Registrazione, login, verifica email, rotazione refresh token, logout, cookie HTTP-only, guardie Origin/Referer, endpoint me |
| 3 | AuthLifecycleSmokeTests |
Rotazione refresh token, logout idempotente, cookie scaduti, prevenzione furto cookie, richieste senza Origin |
| 4 | ContainerBootstrapIntegrationTests |
Health endpoint /api/health/ready: 200 quando DB pronto, 503 quando bootstrap non completato |
| 5 | FilmIntegrationTests |
Ciclo di vita stato film (InCartellone, InArrivo, FuoriCartellone), promozione catalog lifecycle, TMDB ID duplicato, conteggio show |
| 6 | ShowIntegrationTests |
CRUD show, paginazione, filtro per data/cinema/film, rilevamento conflitti orari, occupazione sala, pianificazione batch, publish/unpublish, scope CinemaStaff, film in arrivo |
| 7 | CheckoutIntegrationTests |
Mappa posti, hold posti (creazione, estensione, rilascio, conflitto, concorrenza), creazione ordini con chiavi idempotenza, prezzi per categoria, immutabilità snapshot, guardie show non pubblicati/pubblicati |
| 8 | CheckoutHostedIntegrationTests |
Checkout Stripe hosted: creazione sessione, webhook completamento, riconciliazione, scadenza, pagamento misto (credito+carta), webhook duplicato (idempotenza), fallimento/cancellazione pagamento, auto-scadenza checkout |
| 9 | PagamentoCreditoIntegrationTests |
Flussi pagamento sincrono e misto (Carta, Credito, Misto), addebito credito/audit, ricarica admin, cancellazione ordine pendente, sicurezza replay webhook Stripe |
| 10 | TicketIntegrationTests |
Generazione PDF biglietti, invio email, differenziazione categorie posto nel PDF, controllo accesso download biglietti |
| 11 | AdminUserSecurityIntegrationTests |
Lista/filtro/ricerca utenti admin, flusso invito (PowerUser, Admin, CinemaStaff), promozione/retrocessione ruolo (blocco ultimo admin, utenti social-only, utenti disabilitati), incremento auth version, revoca refresh token su cambio ruolo, endpoint ruoli assegnabili |
| 12 | ExternalAuthIntegrationTests |
Flussi OAuth Google/Microsoft: avvio, callback, code exchange, creazione/linking account, rifiuto ruoli elevati, consumo/invalidazione state, riutilizzo exchange code, email non verificata, account work/personal, nascondere provider non configurati |
| 13 | PasswordCredentialsIntegrationTests |
Cambio password (successo, password corrente errata, rifiuto social-only), login post-cambio, revoca refresh token, incremento auth version, forgot password (messaggio generico, anti-enumerazione, utenti disabilitati), reset password (token valido/invalido/riutilizzato/scaduto, social-only set password), endpoint sicurezza account |
| 14 | AccountTokenIntegrationTests |
Creazione/hashing token, validazione (scopo corretto/errato, token invalido/vuoto/scaduto), consumo (una volta, rifiuto riutilizzo), revoca token esistenti su nuova creazione, audit log, validazione URL redirect |
| 15 | AccountDeletionIntegrationTests |
Export dati utente (JSON), richiesta/conferma cancellazione (token-based), anonimizzazione account (rimozione PII, disabilitazione), cancellazione admin (guardia ultimo admin), toggle abilita/disabilita, revoca assegnazioni CinemaStaff, rimozione external login per ri-registrazione, audit log |
| 16 | DashboardStatsIntegrationTests |
Riepilogo ricavi (settimana corrente/scorsa, mese corrente/scorso, anno, delta), trend ricavi (granularità mensile/settimanale, cumulativo), classifica film, filtro cinema |
| 17 | SettingsIntegrationTests |
GET/PUT impostazioni piattaforma (prezzo base biglietto, buffer minuti, percentuali VIP/Access), validazione (prezzo negativo, buffer fuori range), RBAC (solo Admin), serializzazione UTC |
| 18 | SalaIntegrationTests |
CRUD sale, salvataggio/sostituzione layout posti, categorie posto (Platea, Vip, Access, Galleria), guardie sala disabilitata per show/checkout, conteggio show |
| 19 | RegistaIntegrationTests |
Lista paginata registi con filtro stato film (InCartellone, InArrivo), ordinamento (recenti, nome_az, piu_film), ricerca, verifica conteggio film |
| 20 | ProgrammazioneIntegrationTests |
Programmazione film (tab evidenza/uscita/tutti, filtro cinema, ricerca, filtro categoria, paginazione, esclusione film futuri), lista cinema (ordinamento nome/distanza), scheda film con ShowCalendar, test limiti UTC, set/clear cinema preferito |
| 21 | CategoriaIntegrationTests |
CRUD categorie (lista, creazione, rilevamento duplicati, modifica, cancellazione) |
| 22 | RbacIntegrationTests |
Matrice controllo accessi basata su ruoli: Anonymous → 401, User → 403 su endpoint admin/power, PowerUser → permesso CRUD ma 403 su admin-only, Admin → accesso completo |
| 23 | CorsConfigurationIntegrationTests |
Header CORS per origini permesse/non permesse, preflight, richieste autenticate, upload media |
| 24 | MovieIntegrationTests (TMDB) |
Ricerca TMDB (risultati, rifiuto query troppo corte), import TMDB (crea film con metadati, rilevamento duplicati, RBAC), anteprima film |
| 25 | ApiCanonicalNamespaceIntegrationTests |
Verifica che tutti gli endpoint funzionino sotto /api/*: auth, films, cinemas, shows, checkout, profile, admin, upload media; conferma che gli alias legacy root restituiscano 404 |
| 26 | CinemaStaffAuthorizationIntegrationTests |
Enumerazione ruoli CinemaStaff, tabella assegnazioni, rifiuto social login per staff, invito con/senza assegnazioni, CRUD admin su assegnazioni, endpoint cinema operativi staff, gestione show su cinema autorizzati/non autorizzati |
| 27 | ShowCancellationIntegrationTests |
Cancellazione show (nessun biglietto, ordini pendenti, ordini pagati carta/credito/misti), creazione rimborso Stripe, blocco biglietti validati, blocco show iniziati, gestione ordini checkout-in-progress, webhook Stripe rimborso tardivo, risoluzione revisione manuale, lista cancellazioni |
| 28 | ValidazioneTicketIntegrationTests |
Lookup validazione biglietti, validazione (successo, conflitto doppia validazione, mismatch cinema), visualizzazione categoria posto |
| 29 | LegalAcceptanceIntegrationTests |
Registrazione con/senza accettazione legale, memorizzazione versione documenti legali, requisito accettazione per social login, accettazione legale post-autenticazione, esposizione versione legale nella config frontend |
| 30 | FrontendHostedSmokeTests |
Factory speciale: FrontendWebApplicationFactory (non il CustomWebApplicationFactory standard). Testa il progetto web frontend direttamente: route pubbliche (200), shell HTML route protette, .html legacy (404), header CORS/sicurezza (CSP, X-Frame-Options, Permissions-Policy, Referrer-Policy), disponibilità asset statici (runtime-config.js, tailwind.css, font vendor), documentazione deploy edge, prepare-edge-deploy.mjs (genera artefatti SEO, robots.txt, sitemap.xml, HTML pre-renderizzato), guardie regressione codice sorgente (no stili inline, no innerHTML, no route proxy legacy, no naming unitPrice) |
| 31 | RateLimiterIntegrationTests |
7 test (RL1-RL7): blocco login dopo N tentativi stessa email, email diversa contatore separato, risposta 429 JSON+Retry-After, blocco forgot-password, forgot-password email diversa, X-Forwarded-For diverso contatore separato, body JSON senza email fallback anonimo |
# Tutti i test backend (639 test)
dotnet test tests/backend/FilmAPI.Tests.csproj
# Solo integration test
dotnet test tests/backend/FilmAPI.Tests.csproj --filter "FullyQualifiedName~Integration"
# Esecuzione senza restore (VS Code task)
dotnet test tests/backend/FilmAPI.Tests.csproj --no-restore- Factory centralizzato: tutti i test di integrazione usano
CustomWebApplicationFactory(o sottoclasse) viaIClassFixture<T>. xUnit crea una singola istanza della factory condivisa tra tutti i test della classe. - Database SQLite:
SqliteConnectionaperto inInitializeAsync, usato per creare unFilmDbContextconUseSqlite(_connection). La connessione rimane aperta per tutta la durata dei test (pattern "shared in-memory database"). - Fakes: registrati nel container DI via
builder.ConfigureServices()nel factory, sostituiscono le implementazioni reali. - Configurazione:
ConfigureAppConfigurationconAddInMemoryCollectionper override puliti senza toccare variabili d'ambiente globali. - Progetto di test:
FilmAPI.Tests.csproj(targetnet10.0) referenziaFilmAPI.csproj,FilmApiSeeder.csproj, eCineBase.Web.csproj. Non ci sono file.runsettingsoappsettings.Test.json: tutta la configurazione è programmatica. - Copertura codice:
coverlet.collector6.0.4 integrato.
Playwright è un framework di automazione browser sviluppato da Microsoft. A differenza di strumenti come Jest o Vitest (che eseguono test in un ambiente Node.js simulato), Playwright apre un vero browser Chromium/Edge e ci interagisce esattamente come farebbe un utente reale.
Cosa significa in pratica:
- Il JavaScript del frontend viene eseguito realmente nel browser. Playwright non simula il DOM: carica la pagina, esegue tutti gli script, attende il rendering, e poi interagisce con gli elementi.
- Simula il comportamento utente: click, digitazione, navigazione, scroll, submit di form. Le interazioni sono eventi DOM reali, non mock.
- Può intercettare il traffico di rete:
page.route()permette di mockare le risposte delle API, quindi il frontend viene testato in isolamento dal backend reale. - Cattura screenshot e trace: in caso di fallimento, Playwright salva automaticamente screenshot, video, e trace per il debugging.
Playwright ha due modalità in CineBase:
Playwright usa Chromium (o Edge su Windows) installato sulla macchina. Lancia automaticamente il server frontend via dotnet run e ci connette il browser.
cd frontend/CineBase.Web
# Esegue la suite browser audit
npm run test:browser
# Esegue con browser visibile (non headless)
npm run test:browser:headed
# Valida la coverage matrix + esegue test
npm run test:browser:full
# Valida solo la coverage matrix
npm run test:browser:matrix
# Comando diretto equivalente
npx playwright test -c ../../tests/frontend/playwright.config.cjsPlaywright gira in un container Docker (mcr.microsoft.com/playwright:v1.60.0-noble) contro lo stack completo Docker Compose (MariaDB + backend + frontend reali). In questa modalità, le richieste HTTP sono vere: il browser nel container chiama il frontend e il backend reali nel docker network.
# Avvia lo stack E2E (backend, frontend, MariaDB, Mailpit, seeder)
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example up -d --build
# Esegue il Docker Compose smoke test
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example --profile e2e run --rm --build playwright
# Esegue l'intera suite browser audit nel container
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example --profile e2e run --rm --build playwright test -c playwright.config.cjs browser-audit.spec.cjs
# Spegne lo stack
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example down --remove-orphans| Aspetto | Browser installato | Container Docker |
|---|---|---|
| Backend | Mockato via page.route() |
Reale (stack Docker Compose) |
| Database | Nessuno | MariaDB con dati seeded |
| Velocità | ~2 minuti | ~3 minuti (+ avvio stack) |
| Dipendenze | Node.js, .NET SDK, Chromium/Edge | Solo Docker |
| Isolamento | Fronend isolato dal backend | Test end-to-end reale |
| CI/CD | Adatto a CI leggero (solo frontend) | Adatto a CI completo (stack intero) |
| File | Tipo | Contenuto |
|---|---|---|
playwright.config.cjs |
Configurazione | Browser (Chromium/Edge), timeout 30s, workers=1, headless, trace on failure, webserver auto-start (dotnet run) |
Dockerfile |
Immagine Docker | Basato su mcr.microsoft.com/playwright:v1.60.0-noble, esegue npm ci, entrypoint playwright |
browser-audit.spec.cjs (~2700 righe) |
Suite principale | Testa 34 route del frontend con ~160 stati, usando API mockate via page.route() |
docker-compose.smoke.spec.cjs |
Smoke test Docker | Test contro stack reale: pagine pubbliche, login admin, creazione ordine |
browser-audit.matrix.cjs |
Coverage matrix | Mappa pagina → stati → titoli test con soglie di copertura |
validate-browser-audit-matrix.cjs |
Validatore | Verifica riferimenti matrix, confronta file modificati (git diff) con matrix |
unit/parse-utc-datetime.test.cjs |
Unit test Node.js | 10 suite di test per parseUtcDateTime() |
Finalità: testare il rendering e il comportamento del frontend in isolamento dal backend.
Approccio: usa page.route() di Playwright per intercettare tutte le chiamate API e rispondere con dati mock generati da buildState(). Il frontend non sa di essere mockato: il JavaScript si esegue normalmente, fetcha dati, renderizza componenti, e Playwright verifica che tutto funzioni.
buildState() genera uno stato backend completo in memoria:
- 25 film, 12 cinema, 11 show, 6 ordini, 6 biglietti profilo, 5 utenti
- Categorie, registi, mappe posti, movimenti credito, dati ricavi, impostazioni
Logout testato: ~40 scenari che coprono:
- Pagine pubbliche (home, programmazione, scheda film, pagina legale)
- Flussi autenticati (profilo, acquisto, pagamento, dashboard admin)
- Backoffice admin (film, cinema, categorie, registi, sale, utenti, show, rimborsi, ricariche)
- Flussi auth (login, registrazione, forgot/reset password, social login)
- Validazione biglietti (lookup, validazione, modalità auto)
- Gestione errori e stati vuoti
- Gestione date UTC
Finalità: verificare che lo stack Docker completo funzioni end-to-end.
Approccio: si connette al frontend e backend reali (nessun page.route()) e testa:
- Render pagine pubbliche (200)
- Login admin con credenziali reali
- Pulsanti OAuth nascosti quando provider non configurati
- Caricamento pagina checkout
- Avviso Stripe disabilitato
- Caricamento pagina revisione rimborsi
- Creazione ordine pendente via API
Dipendenze: stack Docker avviato con seeder (admin account, film, show, posti disponibili).
{
testDir: './tests/frontend',
testMatch: '**/*.spec.cjs',
workers: 1, // Esecuzione sequenziale
timeout: 30000, // 30 secondi per test
expect: { timeout: 5000 }, // 5 secondi per assertion
use: {
browserName: 'chromium',
channel: 'msedge', // Edge su Windows
headless: true,
baseURL: process.env.CINEBASE_PLAYWRIGHT_BASE_URL || 'http://localhost:5101',
trace: 'retain-on-failure', // Trace solo su fallimento
},
webServer: !process.env.CINEBASE_USE_EXTERNAL_SERVER ? {
command: 'dotnet run --project frontend/CineBase.Web/CineBase.Web.csproj --no-launch-profile --urls {baseURL}',
timeout: 120000,
} : undefined,
}CINEBASE_PLAYWRIGHT_BASE_URL: override URL frontend (defaulthttp://localhost:5101)CINEBASE_PLAYWRIGHT_API_ORIGIN: override URL backend per i mock (defaulthttp://localhost:5000)CINEBASE_USE_EXTERNAL_SERVER: se'true', Playwright non avviadotnet run(usato nei container Docker dove il server è già in esecuzione)
| Playwright... | Dettaglio |
|---|---|
| Esegue realmente | Il browser (Chromium/Edge), il rendering HTML/CSS, l'esecuzione JavaScript (Web Components, fetch, event listener, state management), il ciclo di vita della pagina (load, DOMContentLoaded, route client-side) |
| Simula | Solo nella suite browser-audit: le risposte API via page.route(). Il JavaScript chiama fetch('/api/...') e Playwright intercetta la richiesta restituendo dati mock. Nella suite docker-compose.smoke: nulla è simulato, tutte le richieste sono reali. |
| Non testa | Il backend (nella suite browser-audit), il database, Stripe, SMTP, OAuth (tutti mockati). Nella suite smoke invece testa l'intero stack. |
tests/frontend/unit/parse-utc-datetime.test.cjs — 10 suite di test che verificano la funzione parseUtcDateTime() del frontend. Usa assert di Node.js (nessun framework). Testa: ISO bare, suffisso Z, solo data, secondi, null/empty, stringhe con offset, regressione vs new Date(), equivalenza epoch, whitespace, compatibilità campi backend.
node tests/frontend/unit/parse-utc-datetime.test.cjs# Tutti i test
dotnet test tests/backend/FilmAPI.Tests.csproj
# Solo unit
dotnet test tests/backend/FilmAPI.Tests.csproj --filter "FullyQualifiedName~Unit"
# Solo integration
dotnet test tests/backend/FilmAPI.Tests.csproj --filter "FullyQualifiedName~Integration"
# Senza restore (task VS Code)
dotnet test tests/backend/FilmAPI.Tests.csproj --no-restorecd frontend/CineBase.Web
npm run test:browser # Suite browser audit
npm run test:browser:headed # Modalità headed (browser visibile)
npm run test:browser:full # Matrix validation + test
npm run test:browser:matrix # Solo matrix validation# Avvio stack
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example up -d --build
# Smoke test
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example --profile e2e run --rm --build playwright
# Suite completa nel container
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example --profile e2e run --rm --build playwright test -c playwright.config.cjs browser-audit.spec.cjs
# Spegnimento stack
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example down --remove-orphansnode tests/frontend/unit/parse-utc-datetime.test.cjs