Przepraszam za nekro w tym poście, ale czuję się zmuszony zastanowić się nad kilkoma rzeczami, które nie wydają się być poruszone.
Przede wszystkim - kiedy podczas testów jednostkowych potrzebujemy dostępu do prywatnych członków klasy, jest to na ogół duża, gruba czerwona flaga, którą wyłudziliśmy w naszym strategicznym lub taktycznym podejściu i nieumyślnie naruszyliśmy jedną zasadę odpowiedzialności, popychając zachowanie, do którego nie należy. Poczucie potrzeby dostępu do metod, które są tak naprawdę niczym więcej niż izolowanym podprogramem procedury budowlanej, jest jednym z najczęstszych tego zjawisk; jednak to trochę tak, jakby twój szef spodziewał się, że przyjdziesz do pracy gotowy, a także mając przewrotną potrzebę wiedzieć, przez jaką poranną rutynę przeszedłeś, aby dostać się do tego stanu ...
Innym najczęstszym przykładem tego zdarzenia jest próba przetestowania przysłowiowej „klasy boga”. Jest to szczególny rodzaj problemu sam w sobie, ale cierpi z powodu tego samego podstawowego problemu z koniecznością poznania szczegółowych szczegółów procedury - ale to zejście z tematu.
W tym konkretnym przykładzie skutecznie przypisaliśmy odpowiedzialność za pełną inicjalizację obiektu Bar do konstruktora klasy FooBar. W programowaniu obiektowym jednym z głównych założeń jest to, że konstruktor jest „święty” i powinien być chroniony przed nieprawidłowymi danymi, które unieważniłyby jego „wewnętrzny stan i pozostawiałyby go do upadku gdzieś indziej (w czym może być bardzo głęboka) rurociąg.)
Nie udało nam się tego tutaj zrobić, pozwalając obiektowi FooBar zaakceptować pasek, który nie jest gotowy w momencie budowy FooBar, i zrekompensowaliśmy go poprzez „hakowanie” obiektu FooBar, aby wziąć sprawy w swoje „własne” ręce.
Wynika to z nieprzestrzegania innej zasady programowania obiektowego (w przypadku Bar), która polega na tym, że stan obiektu powinien być w pełni zainicjowany i gotowy do obsługi wszelkich połączeń przychodzących do jego członków publicznych natychmiast po utworzeniu. Nie oznacza to natychmiast po wywołaniu konstruktora we wszystkich przypadkach. Jeśli masz obiekt, który ma wiele złożonych scenariuszy konstrukcyjnych, lepiej jest wystawić setery do opcjonalnych elementów składowych na obiekt, który jest implementowany zgodnie ze wzorcem projektowym tworzenia (fabryka, konstruktor itp.) W dowolnym te ostatnie przypadki,
W twoim przykładzie właściwość „status” paska nie wydaje się być w prawidłowym stanie, w którym FooBar może to zaakceptować - więc FooBar robi coś, aby rozwiązać ten problem.
Drugi problem, jaki widzę, polega na tym, że wydaje się, że próbujesz przetestować swój kod, zamiast ćwiczyć programowanie oparte na testach. To zdecydowanie moja własna opinia w tym momencie; ale tego typu testy są naprawdę anty-wzorcem. W końcu wpadasz w pułapkę uświadomienia sobie, że masz podstawowe problemy z projektowaniem, które uniemożliwiają testowanie kodu po fakcie, zamiast pisania potrzebnych testów, a następnie programowania do testów. Niezależnie od tego, jak podejdziesz do problemu, powinieneś skończyć z taką samą liczbą testów i linii kodu, jeśli naprawdę osiągnąłeś implementację SOLID. Więc - po co próbować odwracać swoją drogę do kodu, który można przetestować, skoro możesz po prostu rozwiązać ten problem na początku swoich prac programistycznych?
Gdybyś to zrobił, znacznie wcześniej zdałbyś sobie sprawę, że będziesz musiał napisać dość nieprzyjemny kod, aby przetestować swój projekt, i miałbyś możliwość wcześniejszego dostosowania swojego podejścia poprzez zmianę zachowania na implementacje, które są łatwe do przetestowania.