Perdón por el necro en esta publicación, pero me siento obligado a opinar sobre un par de cosas que no parecen haber sido tocadas.
Primero, lo más importante: cuando nos encontramos necesitando acceso a miembros privados en una clase durante las pruebas de la unidad, generalmente es una gran y gruesa bandera roja que nos hemos burlado de nuestro enfoque estratégico o táctico y hemos violado inadvertidamente el principio de responsabilidad individual al presionar comportamiento donde no pertenece. Sentir la necesidad de acceder a métodos que realmente no son más que una subrutina aislada de un procedimiento de construcción es uno de los casos más comunes de esto; sin embargo, es como si tu jefe esperara que aparecieras listo para trabajar y también tuviera una necesidad perversa de saber qué rutina matutina seguiste para llegar a ese estado ...
La otra instancia más común de este suceso es cuando te encuentras tratando de probar la proverbial "clase de dios". Es un tipo especial de problema en sí mismo, pero sufre el mismo problema básico con la necesidad de conocer detalles íntimos de un procedimiento, pero eso está saliendo del tema.
En este ejemplo específico, hemos asignado efectivamente la responsabilidad de inicializar completamente el objeto Bar al constructor de la clase FooBar. En la programación orientada a objetos, uno de los principales núcleos es que el constructor es "sagrado" y debe protegerse contra datos no válidos que invalidarían su propio estado interno y lo dejarían preparado para fallar en otro lugar aguas abajo (en lo que podría ser muy profundo). tubería.)
No hemos podido hacer eso aquí al permitir que el objeto FooBar acepte una barra que no está lista en el momento en que se construye el FooBar, y lo hemos compensado mediante una especie de "pirateo" del objeto FooBar para que tome las cosas en cuenta manos.
Este es el resultado de una falla en adherirse a otra unidad de programación orientada a objetos (en el caso de Bar), que es que el estado de un objeto debe estar completamente inicializado y listo para manejar cualquier llamada entrante a sus miembros públicos inmediatamente después de la creación. Ahora, esto no significa inmediatamente después de que se llame al constructor en todas las instancias. Cuando tiene un objeto que tiene muchos escenarios de construcción complejos, es mejor exponer a los setters a sus miembros opcionales a un objeto que se implemente de acuerdo con un patrón de diseño de creación (Factory, Builder, etc.) en cualquiera de los últimos casos
En su ejemplo, la propiedad "status" de la barra no parece estar en un estado válido en el que un FooBar pueda aceptarla, por lo que FooBar hace algo para corregir ese problema.
El segundo problema que veo es que parece que está intentando probar su código en lugar de practicar el desarrollo basado en pruebas. Esta es definitivamente mi propia opinión en este momento; pero, este tipo de prueba es realmente un antipatrón. Lo que termina haciendo es caer en la trampa de darse cuenta de que tiene problemas centrales de diseño que impiden que su código sea verificable después del hecho, en lugar de escribir las pruebas que necesita y posteriormente programarlas para las pruebas. De cualquier forma que se encuentre con el problema, aún debería terminar con la misma cantidad de pruebas y líneas de código si realmente hubiera logrado una implementación SÓLIDA. Entonces, ¿por qué tratar de aplicar ingeniería inversa en código comprobable cuando puede abordar el asunto al comienzo de sus esfuerzos de desarrollo?
Si lo hubiera hecho, entonces se habría dado cuenta mucho antes de que tendría que escribir un código bastante asqueroso para probar su diseño y habría tenido la oportunidad desde el principio de realinear su enfoque cambiando el comportamiento a implementaciones que son fácilmente comprobables