Odpowiem po kolei, potem tl;dr ;-)
Cytat(Tuminure @ 26.06.2015, 11:38:33 )

Nawet po przetestowaniu każdej metody prywatnej oddzielnie, powinieneś przetestować wspomniane wszystkie kombinacje dla metody publicznej.
Chyba nie do końca się zrozumieliśmy. Nie postuluję za tym, żeby testować wszystkie prywatne jak leci i zrezygnować z testów publicznych. Twierdzę tylko, że czasem testowanie metod prywatnych jest wygodniejsze i bardziej czytelne oraz, że powoduje, że aby wszystko dobrze przetestować należy napisać mniej testów.
Cytat(Tuminure @ 26.06.2015, 11:38:33 )

Błędów, które są nieistotne dla działania klasy.
Zależy co robią te metody prywatne. Poza tym żadne błędy nie są mile widziane.
Cytat(Tuminure @ 26.06.2015, 11:38:33 )

Oznacza to jedynie tyle, że test jest źle napisany (lub jeżeli kolizje błędów zwracają ZAWSZE poprawne wyniki, to test jest napisany dobrze, a wspomniane błędy są nieistotne dla działania).
Jeśli mamy metodę publiczną
pubA(), która wywołuje wewnątrz kilka metod prywatnych przekazując wyniki działania jednej do drugiej. Może się zdarzyć tak, że metoda prywatna
privA() da niewłaściwy wynik, który przekazany do
privB(), a jej wynik przekazany do
privC() finalnie zwróci oczekiwany wynik (np
false). Do czasu, gdy te metody tylko operują na danych wejściowych jest ok - tak jak piszesz, nie ma to znaczenia, bo finalnie jest tak jak powinno być (o ile jest to powtarzalne, a nie dzieje się tak w jednym przypadku na 10). Natomiast jeśli któraś z tych metod przekazuje te dane dalej to może pojawić się problem.
Poza tym odnalezienie błędu jest bardziej problematyczne, bo gdy nie przejdą testy to do sprawdzenia są wszystkie wykorzystane przez publiczną metody prywatne. Nie jest to oczywiście jakiś wielki problem, ale zdecydowanie łatwiej i czytelniej to widać jeśli phpunit pokaże to w samych testach (nie przechodzą testy
privC()). Niż, gdy pokaże, że nie przechodzą testy
pubA() - i błąd może być w każdej z prywatnych metod - sprawdź ręcznie sam.
I jeszcze jedno odnośnie ilości testów.
W przykładzie powyżej użyłem sprawdzenia czy zmienna jest większa, mniejsza czy równa zero. Jeśli takie warunki będziemy mieli w trzech prywatnych metodach to aby przetestować wszystkie przypadki za pomocą testów tylko publicznej metody musimy wygenerować 3x3x3 = 27 przypadków. Testując prywatne metody oddzielnie mamy tylko 3x3 = 9. Oczywiście nie zawsze tak będzie, niemniej są przypadki gdy oddzielne testowanie metod prywatnych zmniejsza ilość testów.
Cytat(Xelah @ 26.06.2015, 12:23:23 )

I to dalej jest nieistotne z punktu widzenia API. Jeśli masz błąd w prywatnej metodzie a API dla dowolnego wejścia produkuje poprawne wyjście, to znaczo to, tyle, że masz błąd w teście. A nie w kodzie.
Zgadzam się, z punktu widzenia API jest nieistotne, ale o ile jest tak jak pisałem wyżej, że prywatne tylko obrabiają dane. Oraz, gdy tak jest dla dowolnego wejścia - tzn błąd jest na swój sposób niezawodny.
Cytat(Xelah @ 26.06.2015, 12:23:23 )

A co Ci mówi fakt, że metoda prywatna zwróciła to, co trzeba? Z punktu widzenia API? Nic. Dosłanie nic. Na pewno nie mówi Ci, że API działa. API i tak będzie przechodziło przez całą ścieżkę i ważne jest, żeby to działało.
API testujesz tak, żeby osiągnąć 100% code-coverage. Wtedy wiesz, że sprawdziłeś każdą ścieżkę (oczywiście nie gwarantuje Ci to braku błędów). Powinieneś też sprawdzić warunki brzegowe, ale to dalej nie ma związku z metodami prywatnymi.
Daje to, że wiemy że ta metoda działa poprawnie. Gdy testy metody publicznej się wysypią to wiemy, że tutaj jest wszystko ok i szukamy błędu gdzie indziej. Nie twierdzę, że testy metod publicznych mają zastąpić testy API ale, że są pomocne.
Testowanie metod prywatnych zwiększa szansę na brak błędów, zmniejsza współczynnik CRAP.
Cytat(Xelah @ 26.06.2015, 12:23:23 )

Nie moge się z tym zgodzić. Bo sugerujesz, że wystarczy sprawidzić dowolne wejście publicznego API i potem sprawdzić prywatne metody i problem z głowy.
W ten sposób przetestowałeś TYLKO wewnetrzne metody a nie API.
Takie pytanie, czy traktujesz tutaj
API na równi z metodami publicznymi, jako zamiennik słowa?
IMHO od tego są właśnie testy jednostkowe - żeby sprawdzić wejścia publicznych i prywatnych metod. Potem są testy integracyjne do sprawdzania pozostałych zależności i przypadków.
Cytat(Xelah @ 26.06.2015, 12:23:23 )

Testy API i tak musisz napisać i tak. Więc pisanie testów dla metod prywatnych zawsze będzie trwało dłużej, a nie przyniesie moim zdaniem żadnych benefitów. Każda, najwet najmniejsza zmiana w implementacji pociągnie za sobą refactoring testów. Bez względu na to czy publiczne API po testach dalej działa czy nie.
Jednym słowem TDD.
Cytat(Xelah @ 26.06.2015, 12:23:23 )

Nieprawda. Testując metody prywatne nie jesteś w stanie przetestować ani jednego scenariusz, bo scenariusz opiera się w 100% na tym co weszło do metody publicznej i jaką ścieżkę wybrała metoda publiczna.
Absolutnie nie przetestujesz w ten sposób różnych scenariuszy a wyłącznie jedną metodę prywatną w oderwaniu od rzeczywistości.
Racja, użyłem złego zwrotu. Nie miałem na myśli scenariuszy jako ścieżek przejścia tylko jako możliwych przypadków/kombinacji.
Chyba właśnie o to chodzi w testach jednostkowych, nie?
Kiedyś widziałem w czyjejś prezentacji, że
unit należy traktować jako najmniejszy możliwy
black box - czarną skrzynkę, która dostaje coś na wejście i wypluwa jakiś wynik. I że właśnie unit testy służą testowaniu takich black box'ów w oderwaniu od otoczenia. Nie ważne jakie inne metody ją wywołują, czy jest publiczna, prywatna czy chroniona. Ważne jakie daje wyniki na podane dane wejściowe.
Cytat(Xelah @ 26.06.2015, 12:23:23 )

Ale to nie problem code-coverage. Testy jednowstkowe powinny testować jednostę. I coverage powinien być tylko na testowanej klasie a nie na jej zależnościach. Twojej klasy nie interesuje, czy metoda get na obiekcie config działa a tym bardziej czy pokrywa jakiś kod. To się da zamockować a sam config sprawdzić własnymi testami. Wtedy nie masz takich problemów.
I wtedy code-coverage pozwala Ci szybko i łatwo wykryć martwy kod. Jeśli coś się nie wykonje to można to usunąć. Proste.
Właśnie o to mi chodziło, że czasem ktoś testuje tylko publiczne API pod kątem coverage, które we wspomnianym przeze mnie przypadku pokaże 100% pokrycia i dziesiątki przejść testów. Pisze testy dla innych klas, zagląda do coverage i widzi 100% dla Config - no to ok, jazda z pozostałymi testami, a takie coverage nic nie oznacza, bo de facto sprawdza tylko wycinek rzeczywistości. To tylko takie moje uczulenie dla tych, którzy rzucili się na coverage jakby to był wyznacznik jakości testów.
tl;drUważam, że można testować metody publiczne. Nie należy jednoznacznie określać, że wystarczy przetestować publiczne wraz ze wszystkimi ścieżkami przejścia (100%) coverage i sprawa załatwiona. Owszem czasem napisanie testów do wielu metod prywatnych trwa dłużej, wymaga więcej refaktoringu przy zmianach w kodzie, ale daje większą stabilność i pozwala szybciej odszukać błąd na podstawie samego wyniku phpunit. Bywa, że napisanie testów do metod prywatnych powoduje, że testów jest mniej, niż w przypadku testowania ich za pomocą publicznych.
Spotkałem się nawet z podejściem testowania metod w jak największym oderwaniu od otoczenia - mockować jak najwięcej, żeby wyniki jednych nie wpływały na wynik testu jednostkowego danej metody. Oczywiście nie ma co popadać w skrajności i testować wszystkie metody prywatne, a potem je mockować przy testach metod publicznych. Niemniej każda funkcja/metoda to ten
unit, który jest tym najmniejszym
black box'em, który można przetestować. Ważne, żeby zachować umiar i nie popadać ze skrajności w skrajność. Dodatkowe testy metod prywatnych nie zaszkodzą, mogą co najwyżej zabrać trochę czasu na ich pisanie i modyfikację.