Désolé pour le nécro sur ce post, mais je me sens obligé de peser sur deux choses qui ne semblent pas avoir été abordées.
Tout d'abord - lorsque nous avons besoin d'accéder à des membres privés sur une classe pendant les tests unitaires, c'est généralement un gros drapeau rouge que nous avons gaffé dans notre approche stratégique ou tactique et avons violé par inadvertance le principe de responsabilité unique en poussant comportement là où il n’appartient pas. Ressentir le besoin d'accéder à des méthodes qui ne sont en réalité rien de plus qu'un sous-programme isolé d'une procédure de construction est l'une des occurrences les plus courantes de ceci; cependant, c'est un peu comme si votre patron s'attend à ce que vous vous présentiez au travail prêt à partir et qu'il ait aussi un besoin pervers de savoir quelle routine matinale vous avez traversée pour vous mettre dans cet état ...
L'autre exemple le plus courant de ce phénomène est celui où vous vous trouvez en train d'essayer de tester la proverbiale «classe de Dieu». C'est un type particulier de problème en soi, mais il souffre du même problème de base avec le besoin de connaître les détails intimes d'une procédure - mais cela sort du sujet.
Dans cet exemple spécifique, nous avons effectivement attribué la responsabilité d'initialiser complètement l'objet Bar au constructeur de la classe FooBar. Dans la programmation orientée objet, l'un des principaux tenants est que le constructeur est "sacré" et doit être protégé contre les données invalides qui invalideraient son propre état interne et le laisseraient prêt à échouer ailleurs en aval (dans ce qui pourrait être un pipeline.)
Nous n'avons pas réussi à le faire ici en permettant à l'objet FooBar d'accepter une barre qui n'est pas prête au moment où la FooBar est construite, et avons compensé en "piratant" l'objet FooBar pour prendre les choses en soi mains.
Ceci est le résultat d'un échec d'adhérer à un autre tenent de la programmation orientée objet (dans le cas de Bar,) qui est que l'état d'un objet doit être entièrement initialisé et prêt à gérer tous les appels entrants à ses `` membres publics '' immédiatement après sa création. Maintenant, cela ne signifie pas immédiatement après l'appel du constructeur dans toutes les instances. Lorsque vous avez un objet qui a de nombreux scénarios de construction complexes, il est préférable d'exposer les setters à ses membres facultatifs à un objet qui est implémenté conformément à un modèle de conception de création (Factory, Builder, etc ...) dans l'un des ces derniers cas,
Dans votre exemple, la propriété "status" de la barre ne semble pas être dans un état valide dans lequel un FooBar peut l'accepter - donc le FooBar fait quelque chose pour corriger ce problème.
Le deuxième problème que je vois est qu'il semble que vous essayez de tester votre code plutôt que de pratiquer le développement piloté par les tests. C'est certainement ma propre opinion en ce moment; mais, ce type de test est vraiment un anti-pattern. Ce que vous finissez par faire, c'est tomber dans le piège de vous rendre compte que vous avez des problèmes de conception fondamentaux qui empêchent votre code d'être testable après coup, plutôt que d'écrire les tests dont vous avez besoin et de programmer ensuite les tests. Quoi qu'il en soit, vous rencontrez le problème, vous devriez toujours vous retrouver avec le même nombre de tests et de lignes de code si vous aviez vraiment réalisé une implémentation SOLID. Alors, pourquoi essayer de faire de l'ingénierie inverse dans un code testable alors que vous pouvez simplement résoudre le problème au début de vos efforts de développement?
Si vous aviez fait cela, alors vous auriez réalisé bien plus tôt que vous alliez devoir écrire du code plutôt dégoûtant afin de le tester par rapport à votre conception et que vous auriez eu l'opportunité dès le début de réaligner votre approche en déplaçant le comportement vers des implémentations qui sont facilement testables.