Sono in un progetto di sistema distribuito scritto in Java dove abbiamo alcune classi che corrispondono a oggetti di business reali molto complessi. Questi oggetti hanno molti metodi corrispondenti alle azioni che l'utente (o qualche altro agente) può applicare a quegli oggetti. Di conseguenza, queste classi sono diventate molto complesse.
L'approccio generale di architettura del sistema ha portato a molti comportamenti concentrati su alcune classi e molti possibili scenari di interazione.
A titolo di esempio e per mantenere le cose facili e chiare, diciamo che Robot e Auto erano classi nel mio progetto.
Quindi, nella classe Robot avrei molti metodi nel seguente schema:
- dormire(); isSleepAvaliable ();
- sveglio(); isAwakeAvaliable ();
- a piedi (direzione); isWalkAvaliable ();
- shoot (direzione); isShootAvaliable ();
- turnOnAlert (); isTurnOnAlertAvailable ();
- turnOffAlert (); isTurnOffAlertAvailable ();
- ricaricare(); isRechargeAvailable ();
- spegni(); isPowerOffAvailable ();
- stepInCar (Car); isStepInCarAvailable ();
- stepOutCar (Car); isStepOutCarAvailable ();
- auto distruzione(); isSelfDestructAvailable ();
- morire(); isDieAvailable ();
- è vivo(); è sveglio(); isAlertOn (); GetBatteryLevel (); getCurrentRidingCar (); getAmmo ();
- ...
Nella classe Car, sarebbe simile:
- accendere(); isTurnOnAvaliable ();
- Spegni(); isTurnOffAvaliable ();
- a piedi (direzione); isWalkAvaliable ();
- Fare rifornimento(); isRefuelAvailable ();
- auto distruzione(); isSelfDestructAvailable ();
- in crash (); isCrashAvailable ();
- isOperational (); Ison (); getFuelLevel (); getCurrentPassenger ();
- ...
Ognuno di questi (robot e auto) è implementato come una macchina a stati, dove alcune azioni sono possibili in alcuni stati e altre no. Le azioni cambiano lo stato dell'oggetto. I metodi di azione vengono generati IllegalStateException
quando chiamati in uno stato non valido e i isXXXAvailable()
metodi indicano se l'azione è possibile al momento. Sebbene alcuni siano facilmente deducibili dallo stato (ad esempio, nello stato di sonno, è disponibile il risveglio), altri non lo sono (per sparare, deve essere sveglio, vivo, munito di munizioni e non in macchina).
Inoltre, anche le interazioni tra gli oggetti sono complesse. Ad esempio, l'auto può contenere solo un passeggero Robot, quindi se un altro tenta di entrare, deve essere generata un'eccezione; Se l'auto si blocca, il passeggero dovrebbe morire; Se il robot è morto all'interno di un veicolo, non può uscire, anche se l'auto stessa è ok; Se il robot si trova all'interno di un'auto, non può entrarne un'altra prima di uscire; eccetera.
Il risultato di questo, è come ho già detto, queste classi sono diventate davvero complesse. A peggiorare le cose, ci sono centinaia di scenari possibili quando il robot e l'auto interagiscono. Inoltre, gran parte di tale logica deve accedere ai dati remoti in altri sistemi. Il risultato è che il test unitario è diventato molto difficile e abbiamo molti problemi di test, uno che causa l'altro in un circolo vizioso:
- Le configurazioni dei test sono molto complesse, perché devono creare un mondo significativamente complesso da esercitare.
- Il numero di test è enorme.
- L'esecuzione della suite di test richiede alcune ore.
- La nostra copertura di test è molto bassa.
- Il codice di test tende a essere scritto settimane o mesi dopo il codice che testano, o mai del tutto.
- Anche molti test vengono interrotti, principalmente perché i requisiti del codice testato sono cambiati.
- Alcuni scenari sono così complessi, che falliscono al timeout durante l'installazione (abbiamo configurato un timeout in ogni test, nel peggiore dei casi 2 minuti e anche questa volta hanno timeout, ci siamo assicurati che non si trattasse di un loop infinito).
- I bug si inseriscono regolarmente nell'ambiente di produzione.
Lo scenario di Robot e auto è una grossolana semplificazione di ciò che abbiamo nella realtà. Chiaramente, questa situazione non è gestibile. Quindi, sto chiedendo aiuto e suggerimenti per: 1, ridurre la complessità delle lezioni; 2. Semplifica gli scenari di interazione tra i miei oggetti; 3. Ridurre i tempi di test e la quantità di codice da testare.
EDIT:
penso di non essere stato chiaro sulle macchine statali. il Robot è esso stesso una macchina a stati, con stati "dormienti", "svegli", "in ricarica", "morti", ecc. La Macchina è un'altra macchina a stati.
EDIT 2: Nel caso in cui tu sia curioso di sapere cosa sia effettivamente il mio sistema, le classi che interagiscono sono cose come Server, indirizzo IP, disco, backup, utente, licenza software, ecc. Lo scenario Robot e auto è solo un caso che ho trovato sarebbe abbastanza semplice da spiegare il mio problema.