Możesz znaleźć nieskończoną listę blogów, artykułów i stron internetowych promujących zalety jednostkowego testowania kodu źródłowego. Jest prawie pewne, że programiści, którzy zaprogramowali kompilatory dla Java, C ++, C # i innych języków pisanych, używali testów jednostkowych do weryfikacji swojej pracy.
Dlaczego więc pomimo popularności testowanie jest nieobecne w składni tych języków?
Microsoft wprowadził LINQ do C # , więc dlaczego nie mogliby również dodać testowania?
Nie chcę przewidzieć, jakie byłyby te zmiany językowe, ale wyjaśnić, dlaczego na początku ich nie ma.
Jako przykład: wiemy, że możesz napisać for
pętlę bez składni for
instrukcji. Możesz użyć while
lub if
/ goto
instrukcji. Ktoś zdecydował, że for
wypowiedź jest bardziej wydajna i wprowadził ją do języka.
Dlaczego testowanie nie następowało po tej samej ewolucji języków programowania?
źródło
Odpowiedzi:
Podobnie jak w przypadku wielu rzeczy, testowanie jednostkowe najlepiej jest obsługiwać na poziomie biblioteki, a nie języka. W szczególności C # ma wiele dostępnych bibliotek testów jednostkowych, a także rzeczy, które są natywne dla .NET Framework, takich jak
Microsoft.VisualStudio.TestTools.UnitTesting
.Każda biblioteka testów jednostkowych ma nieco inną filozofię i składnię testowania. Wszystkie rzeczy są równe, więcej wyborów jest lepszych niż mniej. Gdyby testy jednostkowe zostały wprowadzone do języka, albo byłbyś zamknięty w opcjach projektanta języka, albo używałbyś ... biblioteki i całkowicie unikałbyś funkcji testowania języka.
Przykłady
Nunit - idiomatycznie zaprojektowany framework do testowania jednostek ogólnego przeznaczenia, który w pełni wykorzystuje funkcje języka C #.
Moq - Mocking framework, który w pełni wykorzystuje wyrażenia lambda i drzewa wyrażeń, bez metafory nagrywania / odtwarzania.
Istnieje wiele innych opcji. Biblioteki, takie jak Microsoft Fakes, mogą tworzyć symulatory „shims ...”, które nie wymagają pisania klas za pomocą interfejsów lub metod wirtualnych.
Linq nie jest funkcją językową (pomimo swojej nazwy)
Linq to funkcja biblioteki. Mamy wiele nowych funkcji w samym języku C # za darmo, takich jak wyrażenia lambda i metody rozszerzeń, ale rzeczywista implementacja Linq jest w .NET Framework.
Jest trochę cukru syntaktycznego, który został dodany do C #, aby uczynić instrukcje linq czystszymi, ale ten cukier nie jest wymagany do używania linq.
źródło
var
słowem kluczowym :)Jest wiele powodów. Eric Lippert wielokrotnie twierdził, że powodem tego
feature X
nie jest C #, ponieważ po prostu nie ma tego w budżecie. Projektanci języków nie mają nieskończonej ilości czasu ani pieniędzy na wdrożenie różnych rozwiązań, a każda nowa funkcja wiąże się z kosztami utrzymania. Utrzymanie tak małego języka, jak to tylko możliwe, nie jest tylko łatwiejsze dla projektantów języków - jest także łatwiejsze dla każdego, kto pisze alternatywne implementacje i narzędzia (np. IDE). Dodatkowo, gdy coś jest implementowane pod względem języka, a nie jego części, otrzymujesz przenośność za darmo. Jeśli testowanie jednostkowe jest implementowane jako biblioteka, wystarczy napisać go tylko raz i będzie on działał w dowolnej zgodnej implementacji języka.Warto zauważyć, że D ma obsługę testowania jednostkowego na poziomie składni . Nie wiem, dlaczego postanowili to wrzucić, ale warto zauważyć, że D ma być „językiem programowania systemów na wysokim poziomie”. Projektanci chcieli, aby był on wykonalny dla tego rodzaju niebezpiecznego, niskiego poziomu kodu, do którego tradycyjnie używano C ++, a błąd w niebezpiecznym kodzie jest niezwykle kosztowny - niezdefiniowane zachowanie. Sądzę więc, że mieli dla nich sens dodatkowy wysiłek na wszystko, co pomaga zweryfikować, czy jakiś niebezpieczny kod działa. Na przykład możesz wymusić, aby tylko niektóre zaufane moduły mogły wykonywać niebezpieczne operacje, takie jak niesprawdzony dostęp do tablicy lub arytmetyka wskaźnika.
Szybki rozwój był również dla nich priorytetem, tak bardzo, że uczyniono z niego cel projektowy, który kod D kompiluje wystarczająco szybko, aby był użyteczny jako język skryptowy. Pomaga w tym testowanie jednostek pieczenia bezpośrednio na język, dzięki czemu można uruchomić testy, przekazując kompilatorowi dodatkową flagę.
Myślę jednak, że świetna biblioteka do testowania jednostek nie tylko znajduje jakieś metody i je uruchamia. Weźmy na przykład QuickCheck Haskella , który pozwala przetestować takie rzeczy jak „dla wszystkich x i y
f (x, y) == f (y, x)
”. QuickCheck jest lepiej opisany jako generator testów jednostkowych i pozwala testować rzeczy na wyższym poziomie niż „dla tego wejścia, oczekuję tego wyjścia”. QuickCheck i Linq nie różnią się tak bardzo - oba są językami specyficznymi dla domeny. Zamiast więc dodawać obsługę testów jednostkowych do języka, dlaczego nie dodać funkcji niezbędnych do tego, aby DSL były praktyczne? Skończysz nie tylko testowaniem jednostkowym, ale także lepszym językiem.źródło
Ponieważ testowanie, a zwłaszcza rozwój oparty na testach, jest zjawiskiem głęboko sprzecznym z intuicją.
Prawie każdy programista zaczyna karierę, wierząc, że znacznie lepiej radzi sobie ze złożonością niż w rzeczywistości. Fakt, że nawet największy programista nie jest w stanie pisać dużych i złożonych programów bez poważnych błędów, chyba że użyje wielu testów regresji, jest poważnie rozczarowujący, a nawet wstydliwy dla wielu praktyków. Stąd powszechna niechęć do regularnych testów nawet wśród profesjonalistów, którzy powinni już wiedzieć lepiej.
Myślę, że fakt, że testy religijne powoli stają się coraz bardziej popularne i oczekiwane, wynika w dużej mierze z faktu, że wraz ze wzrostem pojemności pamięci i mocy obliczeniowej budowane są większe niż kiedykolwiek systemy - a wyjątkowo duże systemy są szczególnie podatne na zawiłości, nie można zarządzać bez siatki bezpieczeństwa testów regresyjnych. W rezultacie nawet szczególnie uparci i złudzeni programiści niechętnie przyznają, że potrzebują testowania i zawsze będą musieli testować (jeśli to brzmi jak spowiedź na spotkaniu AA, jest to całkiem celowe - potrzeba sieci bezpieczeństwa jest psychologicznie trudna do zaakceptowania dla wielu osoby).
Większość popularnych obecnie języków pochodzi z wcześniejszej zmiany nastawienia, więc nie mają one wbudowanej obsługi testów: mają
assert
, ale nie mają umów. Jestem całkiem pewien, że jeśli trend się utrzyma, przyszłe języki będą miały większe wsparcie w języku, a nie w bibliotece.źródło
Wiele języków obsługuje testowanie. Twierdzenia C to testy, które program może zawieść. W tym miejscu zatrzymuje się większość języków, ale Eiffel i ostatnio Ada 2012 mają zmienne wstępne (rzeczy, które muszą przejść argumenty funkcji) i postwariantne (rzeczy, które musi przekazać wynik funkcji), przy czym Ada oferuje możliwość odwołania się do początkowych argumentów w postwariant. Ada 2012 oferuje również niezmienniki typów, więc za każdym razem, gdy wywoływana jest metoda w klasie Ada, niezmiennik typu jest sprawdzany przed zwróceniem.
To nie jest typ pełnego testowania, jaki może zapewnić dobry system testowania, ale jest to ważny rodzaj testowania, który najlepiej mogą obsługiwać języki.
źródło
Niektórzy zwolennicy silnie typowanych języków funkcjonalnych twierdzą, że te cechy językowe zmniejszają lub eliminują potrzebę testów jednostkowych.
Dwa, imho, dobrym tego przykładem jest tutaj F # dla zabawy i zysku tutaj i tutaj
Osobiście nadal wierzę w wartość testów jednostkowych, ale są pewne ważne punkty. Np. Jeśli stan niezgodny z prawem jest nieczytelny w kodzie, to nie tylko napisanie testów jednostkowych dla tego przypadku jest niemożliwe.
źródło
Twierdziłbym, że przegapiłeś dodanie niektórych niezbędnych funkcji, ponieważ nie zostały one wyróżnione, jak w przypadku testów jednostkowych .
Na przykład testy jednostkowe w języku C # są oparte głównie na atrybutach. Funkcja Niestandardowe atrybuty zapewnia bogaty mechanizm rozszerzenia, który umożliwia frameworkom takim jak NUnit iterowanie i konkurowanie z takimi funkcjami, jak testy oparte na teorii i parametryzowane .
To prowadzi mnie do drugiego ważnego punktu - nie wiemy wystarczająco dużo o tym, co czyni dobrą testowalność upieczeniem go w języku. Tempo innowacji w testowaniu jest znacznie szybsze niż w innych konstrukcjach językowych, dlatego musimy mieć elastyczne mechanizmy w naszych językach, aby pozostawić swobodę innowacji.
Jestem użytkownikiem, ale nie jestem fanatykiem TDD - w niektórych przypadkach jest to bardzo pomocne, szczególnie w celu poprawy myślenia projektowego. Niekoniecznie jest to przydatne w przypadku starszych systemów - testowanie wyższego poziomu z dobrymi danymi i automatyzacją prawdopodobnie przyniesie więcej korzyści wraz z silną kulturą kontroli kodu .
Inne odpowiednie teksty:
źródło