La prueba unitaria solo es útil si está probando la implementación correcta de dicha función, no el uso correcto, porque una prueba unitaria no puede decir que una función no se llamará desde otro hilo en el resto de su base de código, tal como puede ' Diga que las funciones no se llamarán con parámetros que violen sus condiciones previas (y técnicamente lo que está tratando de probar es básicamente una violación de una condición previa en el uso, que es algo contra lo que no puede probar efectivamente porque la prueba puede ' t restrinja cómo otros lugares en la base de código usan tales funciones; sin embargo, puede probar si las violaciones de las condiciones previas resultan en errores / excepciones apropiados.
Este es un caso de afirmación para mí en la implementación de las funciones relevantes como otros han señalado, o incluso más sofisticado es asegurarse de que las funciones sean seguras para subprocesos (aunque esto no siempre es práctico cuando se trabaja con algunas API).
También solo una nota al margen, pero "main thread"! = "UI thread" en todos los casos. Muchas API GUI no son seguras para subprocesos (y hacer un kit GUI seguro para subprocesos es muy difícil), pero eso no significa que tenga que invocarlas desde el mismo subproceso que tiene el punto de entrada para su aplicación. Eso podría ser útil incluso al implementar sus afirmaciones dentro de las funciones relevantes de la interfaz de usuario para distinguir el "hilo de la interfaz de usuario" del "hilo principal", como capturar el ID del hilo actual cuando se crea una ventana para comparar en lugar de desde el punto de entrada principal de la aplicación (que al menos reduce la cantidad de supuestos / restricciones de uso que la implementación aplica solo a lo que es realmente relevante).
La seguridad de los subprocesos era en realidad el punto de tropiezo de un antiguo equipo mío, y en nuestro caso particular lo habría calificado como la "microoptimización" más contraproducente de todos ellos, de un tipo que generó más costos de mantenimiento que incluso Asamblea manuscrita. Tuvimos una cobertura de código bastante completa en nuestras pruebas unitarias, junto con pruebas de integración bastante sofisticadas, solo para encontrar puntos muertos y condiciones de carrera en el software que eludió nuestras pruebas. Y eso se debió a que los desarrolladores de código multiproceso al azar sin ser conscientes de todos los efectos secundarios que podrían ocurrir en la cadena de llamadas de funciones que resultarían de los suyos, con una idea bastante ingenua de que podrían solucionar esos errores en retrospectiva simplemente lanzando se cierra a izquierda y derecha,
Estaba sesgado en la dirección opuesta, ya que un tipo de la vieja escuela que desconfiaba de los subprocesos múltiples, era un recién llegado a adoptarlo, y pensé que la corrección supera el rendimiento hasta el punto de que rara vez se usen todos estos núcleos que tenemos ahora, hasta que descubrí cosas como funciones puras y diseños inmutables y estructuras de datos persistentes que finalmente me permitieron utilizar completamente ese hardware sin preocuparme en el mundo por las condiciones de carrera y los puntos muertos. Debo admitir que hasta 2010, más o menos, odié el subprocesamiento múltiple con pasión, excepto por algunos bucles paralelos aquí y allá en áreas que son triviales para razonar sobre la seguridad de los hilos, y favorecí mucho más código secuencial para el diseño de productos dado mi dolor con multihilo en antiguos equipos.
Para mí, esa forma de multiprocesar primero y corregir errores más tarde es una estrategia terrible para multiprocesar hasta el punto de casi hacerme odiar la multiproceso inicialmente; puede asegurarse de que sus diseños sean seguros para subprocesos y que sus implementaciones solo utilicen funciones con garantías similares (por ejemplo, funciones puras), o evite el subprocesamiento múltiple. Eso puede parecer un poco dogmático, pero supera descubrir (o peor, no descubrir) problemas difíciles de reproducir en retrospectiva que eluden las pruebas. No tiene sentido optimizar un motor de cohete si eso va a hacer que sea propenso a explotar inesperadamente a mitad de camino a lo largo de su viaje hacia el espacio.
Si inevitablemente tiene que trabajar con código que no es seguro para subprocesos, entonces no lo veo como un problema para resolver con las pruebas de unidad / integración. Lo ideal sería restringir el acceso . Si su código GUI está desacoplado de la lógica empresarial, es posible que pueda aplicar un diseño que restrinja el acceso a dichas llamadas desde cualquier cosa que no sea el hilo / objeto que lo crea *. Ese modo lejano ideal para mí es hacer que sea imposible para otros hilos llamar a esas funciones que intentar asegurarse de que no lo hagan.
- Sí, me doy cuenta de que siempre hay formas de evitar las restricciones de diseño que usted impone, en general, donde el compilador no puede protegerlo. Solo estoy hablando prácticamente; si puede abstraer el objeto "GUI Thread" o lo que sea, entonces podría ser el único que entregó un parámetro a los objetos / funciones GUI, y podría restringir que ese objeto tenga acceso a otros hilos. Por supuesto, podría ser capaz de evitar y cavar profundamente y abrirse camino a través de dichos aros para pasar dichas funciones / objetos GUI a otros hilos para invocar, pero al menos hay una barrera allí, y puede llamar a cualquiera que lo haga un "idiota" ", y no estar equivocado, al menos, por pasar por alto y buscar vacíos en lo que el diseño obviamente intentaba restringir. :-D Eso '