Il test delle unità è utile solo se verifica la corretta implementazione di detta funzione, non l'uso corretto, perché un test unitario non può dire che una funzione non verrà chiamata da un altro thread nel resto della base di codice, proprio come non si può dire che le funzioni non vengano chiamate con parametri che violano le loro precondizioni (e tecnicamente ciò che si sta tentando di testare è fondamentalmente una violazione di una precondizione nell'uso, che è qualcosa a cui non si può testare efficacemente perché il il test non può limitare il modo in cui altri posti nella base di codici usano tali funzioni, ma puoi verificare se le violazioni delle condizioni preliminari portano ad errori / eccezioni approriate, comunque).
Questo è un caso di asserzione per me nell'implementazione delle funzioni rilevanti come alcuni altri hanno sottolineato, o anche più sofisticato è quello di assicurarsi che le funzioni siano sicure per i thread (anche se questo non è sempre pratico quando si lavora con alcuni API).
Anche solo una nota a margine ma "thread principale"!="Thread UI" in tutti i casi. Molte API della GUI non sono thread-safe (e creare un kit GUI thread-safe è dannatamente difficile), ma ciò non significa che devi invocarle dallo stesso thread di quello che ha il punto di ingresso per la tua applicazione. Ciò potrebbe essere utile anche nell'implementare le asserzioni all'interno delle relative funzioni dell'interfaccia utente per distinguere "thread UI" da "thread principale", come catturare l'ID del thread corrente quando viene creata una finestra da confrontare invece che dal punto di ingresso principale dell'applicazione almeno riduce la quantità di ipotesi / limitazioni d'uso che l'implementazione si applica solo a ciò che è veramente rilevante).
La sicurezza del thread era in realtà il punto di partenza "gotcha" in una mia ex squadra, e nel nostro caso specifico l'avrei etichettata come la "micro-ottimizzazione" più controproducente di tutti i tipi che hanno subito più manutenzione costi di un assemblaggio anche a mano. Abbiamo avuto una copertura del codice piuttosto completa nei nostri test unitari, insieme a test di integrazione piuttosto sofisticati, solo per incontrare deadlock e condizioni di gara nel software che ha eluso i nostri test. E questo perché gli sviluppatori hanno codificato a caso codice senza essere consapevoli di ogni singolo effetto collaterale che potrebbe verificarsi nella catena di funzioni chiamate che risulterebbero dalle loro stesse, con un'idea piuttosto ingenua di poter correggere tali errori col senno di poi semplicemente lanciando si blocca a destra e a sinistra, e forse anche a ottenere un falso senso di sicurezza dalla copertura del test *.
I was skewed in the opposite direction as an old school type that distrusted multithreading, was a real latecomer to embracing it, and thought correctness beats performance to the point of rarely ever getting use out of all these cores we have now, until I discovered things like pure functions and immutable designs and persistent data structures which finally allowed me to fully utilize that hardware without a worry in the world about race conditions and deadlocks. I must admit that all the way up until 2010 or so, I hated multithreading with a passion except for a few parallel loops here and there in areas that are trivial to reason about thread-safety, and favored much more sequential code for the design of products given my grief with multithreading in former teams.
Per me, il modo di multithreading prima e correggere bug in seguito è una strategia terribile per il multithreading al punto da farmi odiare inizialmente il multithreading; o assicurati che i tuoi progetti siano sicuri per i thread e che le loro implementazioni utilizzino solo funzioni con garanzie simili (ad es. funzioni pure), oppure eviti il multithreading. Ciò potrebbe sembrare un po 'dogmatico, ma è meglio scoprire (o peggio, non scoprire) problemi difficili da riprodurre con il senno di poi che sfuggono ai test. Non ha senso ottimizzare un motore a razzo se questo si tradurrà nel renderlo incline a esplodere improvvisamente dal nulla a metà del suo viaggio verso lo spazio.
Se si deve inevitabilmente lavorare con codice che non è thread-safe, allora non lo vedo come un problema da risolvere con test di unità / integrazione. L'ideale sarebbe limitare l'accesso . Se il codice della GUI è disgiunto dalla logica aziendale, è possibile applicare un disegno che limiti l'accesso a tali chiamate da qualsiasi cosa che non sia il thread / oggetto che lo crea *. Questa è la modalità ideale per me è quella di rendere impossibile per gli altri thread chiamare quelle funzioni piuttosto che cercare di assicurarmi che non lo facciano.
- Yes, I realize that there's always ways around whatever design restrictions you enforce typically where the compiler can't protect you. I'm just speaking practically; if you can abstract "GUI Thread" object or whatever, then it might be the only one handed a parameter to the GUI objects/functions, and you might be able to restrict that object from having access to other threads. Of course it might be able to bypass and dig deep and work its way around such hoops to pass said GUI functions/objects to other threads to invoke, but at least there's a barrier there, and you can call anyone who does that an "idiot", and not be in the wrong, at least, for clearly bypassing and seeking loopholes for what the design obviously was attempting to restrict. :-D That's actually a very practical litmus test to me is like how confidently you can call someone an "idiot" in misusing a design, without the risk of you actually being the idiot for designing something prone to misuse.