Jeśli masz wyliczenie tylko z wartościami (nie ma metod, które można wykonać w Javie), a wyliczenie to jest częścią biznesowej definicji systemu, czy należy napisać dla niego testy jednostkowe?
Myślałem, że powinny być napisane, nawet jeśli mogłyby wydawać się proste i zbędne. Uważam, że to, co dotyczy specyfikacji biznesowej, powinno być wyraźnie napisane w teście, czy to z jednostką / integracją / interfejsem użytkownika / itp. testy lub przy użyciu systemu typów języka jako metody testowania. Ponieważ wartości, które musi mieć wyliczenie (np. W Javie), z punktu widzenia biznesu, nie mogą być testowane przy użyciu systemu typów, myślę, że powinien istnieć test jednostkowy.
To pytanie nie jest podobne do tego, ponieważ nie dotyczy tego samego problemu, co moje. W tym pytaniu jest funkcja biznesowa (savePeople), a osoba pyta o implementację wewnętrzną (forEach). Tam jest środkowa warstwa biznesowa (funkcja save people), która zawiera konstrukcję językową (forEach). Tutaj konstrukcja języka (enum) jest używana do określenia zachowania z biznesowego punktu widzenia.
W tym przypadku szczegół implementacji pokrywa się z „prawdziwą naturą” danych, to znaczy: zbiorem (w sensie matematycznym) wartości. Można prawdopodobnie użyć niezmiennego zestawu, ale te same wartości powinny nadal tam być. Jeśli używasz tablicy, to samo należy zrobić, aby przetestować logikę biznesową. Myślę, że tutaj zagadką jest to, że konstrukcja języka bardzo dobrze pokrywa się z charakterem danych. Nie jestem pewien, czy wytłumaczyłem się poprawnie
źródło
Odpowiedzi:
Nie, to tylko stan.
Zasadniczo fakt, że używasz wyliczenia, jest szczegółem implementacji ; jest to coś, co możesz chcieć zmienić na inny projekt.
Testowanie wyliczeń pod kątem kompletności jest analogiczne do sprawdzania, czy obecne są wszystkie reprezentowalne liczby całkowite.
Testowanie zachowań obsługiwanych przez wyliczenia jest jednak dobrym pomysłem. Innymi słowy, jeśli zaczniesz od pozytywnego zestawu testów i skomentujesz dowolną pojedynczą wartość wyliczenia, to co najmniej jeden test powinien zakończyć się niepowodzeniem (błędy kompilacji są uważane za niepowodzenia).
źródło
Hearts
,Spades
,Diamonds
,Clubs
], jeśli Czy kiedykolwiek karty, jeśli karta jest czerwona / czarna?null_ptr
błąd. Teraz ma kod błędu przez wyliczanie. Kod sprawdzający:null_ptr
błędu również wyszukuje kod za pomocą wyliczenia. Może więc mieć wartość5
(np.). Teraz musisz dodać kolejny kod błędu. Wyliczenie zostało zmienione (powiedzmy, że dodajemy nowe na górze wyliczenia) Wartośćnull_ptr
wynosi teraz6
. Czy to problem? teraz zwracasz kod błędu6
i testujesz6
. Tak długo, jak wszystko jest logicznie spójne, nic ci nie jest, mimo że ta zmiana przełamuje twój test teoretyczny.Nie testujesz deklaracji enum . Możesz sprawdzić, czy wejście / wyjście funkcji ma oczekiwane wartości wyliczenia. Przykład:
Państwo nie pisać testy sprawdzające następnie ENUM
Parity
definiuje nazwyEven
iOdd
. Taki test byłby bezcelowy, ponieważ wystarczyłoby powtórzyć to, co zostało już określone w kodzie. Powiedzenie tego samego dwa razy nie poprawi tego.Ci zrobić testy weryfikujące zapisu
GetParity
głosu powróciEven
do 0,Odd
dla 1 i tak dalej. Jest to cenne, ponieważ nie powtarzasz kodu, weryfikujesz zachowanie kodu, niezależnie od implementacji. Gdyby kod w środkuGetParity
został całkowicie przepisany, testy byłyby nadal ważne. Rzeczywiście, główne zalety testów jednostkowych polegają na tym, że dają one swobodę bezpiecznego przepisywania i ponownego kodowania kodu, zapewniając, że kod nadal działa zgodnie z oczekiwaniami.Ale jeśli masz test, który zapewnia, że deklaracja wyliczenia określa oczekiwane nazwy, to każda zmiana, którą wprowadzisz w wyliczeniu w przyszłości, będzie wymagać również zmiany testu. Oznacza to, że nie jest to tylko dwa razy więcej pracy, ale oznacza to również utratę wszelkich korzyści z testu jednostkowego. Jeśli musisz zmienić kod i przetestować w tym samym czasie , nie ma zabezpieczenia przed wprowadzaniem błędów.
źródło
Jeśli istnieje ryzyko, że zmiana wyliczenia spowoduje uszkodzenie kodu, to na pewno wszystko z atrybutem [Flagi] w języku C # byłoby dobrym rozwiązaniem, ponieważ dodanie wartości między 2 a 4 (3) byłoby bitowe 1 i 2 zamiast dyskretny przedmiot.
To warstwa ochrony.
Powinieneś rozważyć zastosowanie enum kodeksu postępowania, który znają wszyscy programiści. Nie polegaj na tekstowych reprezentacjach wyliczenia jest częstym, ale może to kolidować z twoimi wytycznymi serializacji.
Widziałem, jak ludzie „poprawiają” wielkie litery wpisów enum, sortują je alfabetycznie lub według innych logicznych grup, z których wszystkie złamały inne części złego kodu.
źródło
Nie, test sprawdzający, czy wyliczenie zawiera wszystkie prawidłowe wartości i nic więcej zasadniczo nie powtarza deklaracji wyliczenia. Testowałbyś tylko, czy język poprawnie implementuje konstrukcję enum, co jest testem bezsensownym.
To powiedziawszy, powinieneś przetestować zachowanie, które zależy od wartości wyliczeniowych. Na przykład, jeśli używasz wartości wyliczania do szeregowania bytów do json lub cokolwiek, lub przechowujesz wartości w bazie danych, powinieneś przetestować zachowanie dla wszystkich wartości wyliczenia. W ten sposób, jeśli wyliczenie zostanie zmodyfikowane, przynajmniej jeden z testów powinien zakończyć się niepowodzeniem. W każdym razie testowałbyś zachowanie wokół twojego wyliczenia, a nie samą deklarację wyliczania.
źródło
Twój kod powinien działać poprawnie niezależnie od rzeczywistych wartości wyliczenia. W takim przypadku nie są wymagane żadne testy jednostkowe.
Ale możesz mieć kod, w którym zmiana wartości wyliczeniowej spowoduje uszkodzenie. Na przykład, jeśli wartość wyliczenia jest przechowywana w pliku zewnętrznym, a po zmianie wartości wyliczenia odczytanie pliku zewnętrznego da zły wynik. W takim przypadku będziesz mieć WIELKI komentarz w pobliżu wyliczenia, ostrzegający nikogo, aby nie modyfikował żadnych wartości, i możesz bardzo dobrze napisać test jednostkowy, który sprawdza wartości liczbowe.
źródło
Ogólnie rzecz biorąc, samo sprawdzenie, czy wyliczenie ma zakodowaną listę wartości, nie ma dużej wartości, jak powiedziano w innych odpowiedziach, ponieważ wtedy wystarczy zaktualizować test i wyliczyć razem.
Kiedyś miałem przypadek, że jeden moduł używał typów wyliczeń z dwóch innych modułów i mapował między nimi. (Jedna z wyliczeń miała dodatkową logikę, druga dotyczyła dostępu do bazy danych, obie miały zależności, które powinny być od siebie odizolowane).
W tym przypadku dodałem test (w module odwzorowania), który zweryfikował, że wszystkie wpisy wyliczenia w wyliczeniu źródłowym istnieją również w wyliczeniu docelowym (a zatem, że odwzorowanie zawsze będzie działać). (W niektórych przypadkach sprawdziłem też na odwrót).
W ten sposób, gdy ktoś dodał wpis do jednego z wyliczeń i zapomniał dodać odpowiedni wpis do drugiego, test zaczął się nie udać.
źródło
Wyliczenia są po prostu typami skończonymi o niestandardowych (miejmy nadzieję znaczących) nazwach. Wyliczenie może mieć tylko jedną wartość, np.
void
Która zawiera tylkonull
(niektóre języki nazywają tounit
i używają nazwyvoid
wyliczenia bez elementów!). Może mieć dwie wartości, takie jakbool
która mafalse
itrue
. Może mieć trzy, jakcolourChannel
zred
,green
iblue
. I tak dalej.Jeśli dwa wyliczenia mają tę samą liczbę wartości, wówczas są „izomorficzne”; tzn. jeśli będziemy systematycznie zamieniać wszystkie nazwy, możemy użyć jednego zamiast drugiego, a nasz program nie będzie się zachowywał inaczej. W szczególności nasze testy nie będą się zachowywać inaczej!
Na przykład,
result
zawierającegowin
/lose
/draw
jest izomorficzna z powyższymcolourChannel
, ponieważ możemy wymienić na przykładcolourChannel
zresult
,red
zwin
,green
zlose
iblue
zdraw
, i tak długo, jak to zrobić wszędzie (producentów i konsumentów, parser i serialisers, wpisy do bazy danych, pliki dziennika itp ), wówczas w naszym programie nie będzie żadnych zmian. Wszelkie „colourChannel
testy”, które napisaliśmy, nadal będą zaliczane, nawet jeśli nie macolourChannel
!Ponadto, jeśli wyliczenie zawiera więcej niż jedną wartość, zawsze możemy zmienić te wartości, aby uzyskać nowy wyliczenie z taką samą liczbą wartości. Ponieważ liczba wartości się nie zmieniła, nowy układ jest izomorficzny w stosunku do starego, a zatem moglibyśmy zmienić wszystkie nazwy, a nasze testy nadal by się udały (pamiętaj, że nie możemy po prostu zmienić definicji; musimy nadal wyłącz wszystkie witryny użytkowania).
Oznacza to, że w odniesieniu do maszyny, wyliczenia są „nazwami rozróżnialnymi” i niczym więcej . Jedyne, co możemy zrobić z wyliczeniem, to ustalić, czy dwie wartości są takie same (np.
red
/red
) Czy różne (np.red
/blue
). Jest to jedyna rzecz, jaką może zrobić „test jednostkowy”, npJak mówi @ jesm00, taki test sprawdza raczej implementację języka niż program. Testy te nigdy nie są dobrym pomysłem: nawet jeśli nie ufasz implementacji języka, powinieneś przetestować ją z zewnątrz , ponieważ nie można ufać, że poprawnie uruchomi testy!
To jest teoria; co z praktyką? Głównym problemem związanym z tą charakterystyką wyliczeń jest to, że programy z „prawdziwego świata” rzadko są samodzielne: mamy starsze wersje, wdrożenia zdalne / osadzone, dane historyczne, kopie zapasowe, bazy danych na żywo itp., Więc nigdy nie możemy tak naprawdę „zmienić się” wszystkie wystąpienia nazwy bez utraty niektórych zastosowań.
Jednak takie rzeczy nie są „odpowiedzialnością” samego wyliczenia: zmiana wyliczenia może przerwać komunikację ze zdalnym systemem, ale odwrotnie możemy to naprawić taki problem, zmieniając wyliczenie!
W takich sytuacjach, enum jest czerwony śledź: co, jeśli jeden system musi to być ten sposób, a inny musi to być to sposób? Nie może to być jedno i drugie, bez względu na to, ile testów piszemy! Prawdziwym winowajcą jest tutaj interfejs wejścia / wyjścia, który powinien produkować / konsumować dobrze zdefiniowane formaty, a nie „dowolną liczbę całkowitą, jaką wybiera interpretacja”. Tak więc prawdziwym rozwiązaniem jest przetestowanie interfejsów we / wy : z testami jednostkowymi, aby sprawdzić, czy parsuje / drukuje oczekiwany format, oraz z testami integracyjnymi, aby sprawdzić, czy format jest rzeczywiście akceptowany przez drugą stronę.
Wciąż możemy się zastanawiać, czy wyliczenie jest „wystarczająco dokładnie wykonywane”, ale w tym przypadku wyliczenie to znów śledź czerwony. To, co nas tak naprawdę martwi, to sam zestaw testowy . Możemy zyskać zaufanie tutaj na kilka sposobów:
red
i testujemy tylkored
, mamy 100% pokrycia. Kontroler właściwości (spróbuje) wygenerować kontrprzykłady do naszych twierdzeń, takich jak generowanie wartościgreen
iblue
, o których zapomnieliśmy przetestować.źródło
Nie. Testy jednostkowe służą do testowania jednostek.
https://en.wikipedia.org/wiki/Unit_testing
Zautomatyzowanym testem dla zadeklarowanego wyliczenia będzie testowanie integralności języka i platformy, na której działa, a nie logika w kodzie autorstwa autora. Nie miałoby to żadnego pożytecznego celu - dołączona dokumentacja, ponieważ kod deklarujący wyliczenie służy zarówno jako dokumentacja, jak i kod, który by to przetestował.
źródło
Oczekuje się, że przetestujesz obserwowalne zachowanie twojego kodu, wpływ wywołań metod / funkcji na obserwowalny stan. Tak długo, jak kod działa prawidłowo, nie musisz testować niczego innego.
Nie musisz jawnie stwierdzać, że typ wyliczenia zawiera wpisy, których się spodziewasz, podobnie jak nie stwierdzasz wprost, że klasa faktycznie istnieje lub że ma metody i atrybuty, których oczekujesz.
W rzeczywistości, testując zachowanie, domyślnie zapewniasz, że klasy, metody i wartości uczestniczące w teście istnieją, więc nie musisz tego jawnie potwierdzać.
Pamiętaj, że do poprawnego działania kodu nie potrzebujesz sensownych nazw, to tylko wygoda dla osób czytających Twój kod. Można zrobić swoją pracę kod z wartościami enum takich jak
foo
,bar
... jak i metodfrobnicate()
.źródło