Testy jednostkowe dla naukowej biblioteki komputerowej

15

Wcześniej miałem trochę doświadczenia w testowaniu jednostkowym, w tym, co nazywam (nie pejoratywnie) klasycznym projektem inżynierii oprogramowania: MVC, z graficznym interfejsem użytkownika, bazą danych, logiką biznesową w warstwie środkowej itp. Teraz „ piszę naukową bibliotekę komputerową w C # (tak, wiem, że C # jest zbyt wolny, używaj C, nie wymyślaj ponownie koła i tak dalej, ale mamy wielu ludzi wykonujących obliczenia naukowe na moim wydziale w C #, i tego potrzebujemy). To mały projekt, jeśli chodzi o branżę programistyczną, ponieważ piszę go głównie sam i od czasu do czasu z pomocą kilku kolegów. Ponadto nie otrzymuję za to zapłaty, a co najważniejsze, jest to projekt akademicki. To znaczy, spodziewam się, że któregoś dnia będzie miał profesjonalną jakość, ponieważ planuję przejść na open source,

W każdym razie projekt staje się duży (około 18 000 linii kodu, co myślę, że jest duży dla projektu jednego człowieka) i wymyka mi się z rąk. Używam git do kontroli źródła i myślę, że wszystko w porządku, ale testuję jak w starej szkole, to znaczy piszę aplikacje na konsole, które testują dużą część systemu, głównie dlatego, że nie mam pojęcia, jak to zrobić wykonać testy jednostkowe w tym scenariuszu, chociaż uważam, że właśnie to powinienem zrobić. Problem polega na tym, że biblioteka zawiera głównie algorytmy, na przykład algorytmy grafowe, klasyfikatory, solwery numeryczne, losowe rozkłady itp. Po prostu nie wiem, jak określić małe przypadki testowe dla każdego z tych algorytmów, a ponieważ wiele z nich jest stochastyczny Nie wiem, jak zweryfikować poprawność. Na przykład do klasyfikacji są niektóre wskaźniki, takie jak precyzja i przywołanie, ale te wskaźniki są lepsze do porównywania dwóch algorytmów niż do oceny jednego algorytmu. Jak mogę tutaj zdefiniować poprawność?

Wreszcie istnieje również problem wydajności. Wiem, że jest to zupełnie inny zestaw testów, ale wydajność jest jedną z ważnych cech narzędzi naukowych, a nie satysfakcji użytkownika lub innych mierników inżynierii oprogramowania.

Jednym z moich największych problemów jest struktura danych. Jedynym testem, jaki mogę wymyślić dla drzewa kd, jest test warunków skrajnych: wstaw wiele losowych wektorów, a następnie wykonaj wiele losowych zapytań i porównaj z naiwnym wyszukiwaniem liniowym. To samo dotyczy wydajności. Z optymalizatorami numerycznymi mam funkcje testowe, które mogę przetestować, ale z drugiej strony jest to test warunków skrajnych. Nie sądzę, aby testy te można było zaklasyfikować jako testy jednostkowe, a co najważniejsze, działały nieprzerwanie, ponieważ większość z nich jest dość ciężka. Ale myślę też, że te testy muszą zostać wykonane, nie mogę po prostu wstawić dwóch elementów, wcisnąć root, i tak, to działa w przypadku 0-1-n.

Jakie zatem jest podejście testowe (jednostkowe) dla tego rodzaju oprogramowania? I jak zorganizować testy jednostkowe i te ciężkie wokół cyklu budowania kodu-zatwierdzania-integracji?

Alejandro Piad
źródło

Odpowiedzi:

19

Powiedziałbym, że obliczenia naukowe są w rzeczywistości dość dobrze przystosowane do testów jednostkowych. Masz określone dane wejściowe i wyjściowe, jasno określone warunki wstępne i końcowe, które prawdopodobnie nie będą się zmieniać co drugi tydzień, zgodnie z zachciankami niektórych projektantów, i żadnych trudnych do przetestowania wymagań dotyczących interfejsu użytkownika.

Wymieniasz niektóre elementy, które mogą powodować problemy; oto co z nimi zrobić:

  • algorytmy losowe: istnieją dwie możliwości. Jeśli rzeczywiście chcesz przetestować randomizację, po prostu zaplanuj dużą liczbę powtórzeń i zapewnij, że oczekiwany odsetek przypadków spełnia pożądane kryterium, z wystarczająco dużymi marginesami błędów, że fałszywe niepowodzenia testów będą dość rzadkie. (Pakiet testowy, który nierzetelnie sygnalizuje błędy fantomowe, jest znacznie gorszy niż taki, który nie wychwytuje wszystkich możliwych błędów ). Alternatywnie, użyj konfigurowalnego losowego źródła i zamień zegar systemowy (lub cokolwiek go używasz) na źródło deterministyczne poprzez zależność zastrzyk, aby Twoje testy stały się w pełni przewidywalne.
  • algorytmy zdefiniowane tylko w kategoriach precyzji / przywoływania: nic nie stoi na przeszkodzie, aby wstawić cały zestaw przypadków wejściowych i zmierzyć precyzję i przywoływanie poprzez dodanie ich wszystkich; to tylko kwestia półautomatycznego generowania takich przypadków testowych skutecznie, aby dostarczanie danych testowych nie stało się przeszkodą dla wydajności. Alternatywnie, określenie pewnych rozsądnie wybranych par wejścia / wyjścia i stwierdzenie, że algorytm oblicza dokładnie pożądane dane wejściowe, może również działać, jeśli procedura jest wystarczająco przewidywalna.
  • wymagania niefunkcjonalne: Jeśli specyfikacja naprawdę określa wyraźne wymagania dotyczące miejsca / czasu, to po prostu musisz uruchomić całe pakiety par danych wejściowych / wyjściowych i sprawdzić, czy wykorzystanie zasobów jest w przybliżeniu zgodne z wymaganym wzorcem użytkowania. Sztuczka polega na tym, aby najpierw skalibrować własną klasę testów, aby nie mierzyć dziesięciu problemów z różnymi rozmiarami, które ostatecznie są zbyt szybkie do zmierzenia lub które trwają tak długo, że uruchomienie zestawu testów staje się niepraktyczne. Możesz nawet napisać generator małych przypadków użycia, który tworzy przypadki testowe o różnych rozmiarach, w zależności od tego, jak szybko działa PU.
  • szybkie i wolno działające testy: czy to testy jednostkowe czy integracyjne, często kończy się wiele bardzo szybkich testów i kilka bardzo powolnych. Ponieważ regularne przeprowadzanie testów jest bardzo cenne, zwykle wybieram pragmatyczną ścieżkę i dzielę wszystko, co mam, na szybki i wolny pakiet, aby szybki mógł działać tak często, jak to możliwe (na pewno przed każdym zatwierdzeniem) i nieważne, czy dwa testy „semantycznie” należą do siebie lub nie.
Kilian Foth
źródło
+1. Wielkie dzięki, w waszej odpowiedzi jest bardzo dużo wglądu. Tylko kilka pytań: Co powiesz na algorytmy optymalizacji, takie jak meta-heurystyka. Mam wiele funkcji testowych, ale wszystko, co mogę z nimi zrobić, to porównanie dwóch różnych algorytmów. Czy muszę również znaleźć algorytm testu porównawczego? Co to znaczy, że algorytm genetyczny jest poprawny? Jak przetestować każdą z „parametryzowalnych” strategii, takich jak rodzaj rekombinacji i mutacji itp.?
Alejandro Piad
1
W przypadku meta-heurystyki zdecydowałbym się wybrać kilka charakterystycznych par We / Wy, tj. „Słynne sukcesy” rutyny, i zweryfikować, czy metoda (lub lepsza z nich) faktycznie znajduje to rozwiązanie. Problemy z „wybieraniem czereśni”, które zdarzają się dobrze, są oczywiście nie-nie w badaniach optymalizacyjnych, ale w testowaniu oprogramowania nie stanowi to problemu - nie zapewniasz jakości algorytmu, tylko poprawną implementację. To jedyna „poprawność”, którą możesz udowodnić. Co do wielokrotnie parametryzowalnych procedur: tak, obawiam się, że wymaga to kombinatorycznej liczby testów ...
Kilian Foth
Czy to tak, jakby zaprojektować banalny test porównawczy, który wszystkie poprawne wdrożenia powinny dokładnie rozwiązać? Czy istnieje sposób na udowodnienie jakości algorytmu? Wiem, że przez większość czasu nie mogę zdefiniować standardu jakości, ale przynajmniej chciałbym, aby żadna zmiana nie obniżyła osiągniętej jakości?
Alejandro Piad