Załóżmy, że zaczynam rozwijać grę RPG z postaciami atakującymi inne postacie i tym podobne rzeczy.
Stosując TDD, wykonuję kilka przypadków testowych w celu przetestowania logiki wewnątrz Character.receiveAttack(Int)
metody. Coś takiego:
@Test
fun healthIsReducedWhenCharacterIsAttacked() {
val c = Character(100) //arg is the health
c.receiveAttack(50) //arg is the suffered attack damage
assertThat(c.health, is(50));
}
Powiedz, że mam 10 metod testowania receiveAttack
metod. Teraz dodaję metodę Character.attack(Character)
(która wywołuje receiveAttack
metodę) i po przetestowaniu jej przez niektóre cykle TDD podejmuję decyzję: Character.receiveAttack(Int)
powinno być private
.
Co dzieje się z poprzednimi 10 testami? Czy powinienem je usunąć? Czy powinienem zachować metodę public
(nie sądzę)?
To pytanie nie dotyczy tego, jak przetestować prywatne metody, ale jak sobie z nimi poradzić po przeprojektowaniu podczas stosowania TDD
object-oriented-design
tdd
Zabijaka
źródło
źródło
internal
lub odpowiednik twojego języka, aby nadal nie była narażona. W rzeczywistości odpowiedź Kevina Cline'a jest tego rodzaju podejściem.Odpowiedzi:
W TDD testy służą jako wykonywalna dokumentacja twojego projektu. Twój projekt się zmienił, więc oczywiście twoja dokumentacja również musi!
Zauważ, że w TDD jedynym sposobem, w jaki
attack
metoda mogła się pojawić, jest wynik pozytywnego wyniku testu. Co oznacza,attack
że jest testowany przez inny test. Co oznacza, że pośrednioreceiveAttack
jest objętyattack
testami. Idealnie, każda zmianareceiveAttack
powinna przerwać przynajmniej jeden zattack
testów.A jeśli nie, to funkcjonalność
receiveAttack
nie jest już potrzebna i nie powinna już istnieć!Ponieważ
receiveAttack
jest już przetestowanyattack
, nie ma znaczenia, czy zachowasz testy. Jeśli środowisko testowe ułatwia testowanie metod prywatnych, a jeśli zdecydujesz się przetestować metody prywatne, możesz je zachować. Ale możesz je również usunąć bez utraty zasięgu testu i pewności siebie.źródło
Jeśli metoda jest na tyle złożona, że wymaga testów, powinna być publiczna w niektórych klasach. Refaktoryzujesz więc z:
do:
Przenieś bieżący test X.complexity na ComplexityTest. Następnie napisz X. coś przez wyśmiewanie się ze złożoności.
Z mojego doświadczenia wynika, że refaktoryzacja w kierunku mniejszych klas i krótszych metod przynosi ogromne korzyści. Są łatwiejsze do zrozumienia, łatwiejsze do przetestowania, a w końcu są wykorzystywane więcej niż można by się spodziewać.
źródło
this.health = this.health - attackDamage
). Być może wyodrębnienie go do innej klasy jest na razie rozwiązaniem nadinżynieryjnym.Należy pamiętać o tym, że podejmujesz decyzję o usunięciu metody z interfejsu API . Sugerują to uprzejmości związane z kompatybilnością wsteczną
Testy są usuwane / lub zastępowane, gdy interfejs API nie obsługuje już tej metody. W tym momencie metoda prywatna jest szczegółem implementacji, który powinien być w stanie refaktoryzować.
W tym momencie powracasz do standardowego pytania, czy Twój zestaw testów powinien bezpośrednio uzyskiwać dostęp do implementacji, czy raczej wchodzić w interakcje wyłącznie za pośrednictwem publicznego interfejsu API. Prywatna metoda jest czymś, co powinniśmy być w stanie zastąpić bez przeszkadzania pakietowi testów . Spodziewałbym się więc, że testy się odejdą - albo przejdzie na emeryturę, albo przejdzie wraz z implementacją do osobno testowalnego komponentu.
źródło