Jestem członkiem klubu robotyki w mojej szkole średniej i jestem odpowiedzialny za programowanie robota. Jedną z sugestii, które wciąż słyszę od różnych dorosłych, jest to, że powinienem pisać testy jednostkowe, aby pomóc w sprawdzeniu poprawności mojego kodu. Baza kodu staje się trochę duża i zgadzam się, że testy jednostkowe byłyby bardzo pomocne w szybszym wykrywaniu błędów.
Nie jestem jednak do końca pewien, jak to osiągnąć. Według mojej najlepszej wiedzy, testowanie jednostkowe odbywa się poprzez pobranie funkcji (lub podsystemu kodu) i dostarczenie jej zestawu danych wejściowych, aby upewnić się, że za każdym razem wychodzi z tym samym wyjściem. Kod, który obecnie posiadam, nie powoduje poważnych awarii danych, a raczej bezpośrednio manipuluje elementami sprzętowymi robota. Większość złożoności wynika z upewnienia się, że elektronika jest sprawna, że kod w tej chwili odpowiada rzeczywistemu sprzętowi robota itp. Często widzę tylko problem z załadowaniem kodu do samego robota, i próba uruchomienia.
Jak można napisać testy jednostkowe kodu, który ma obsługiwać dowolne urządzenie mechaniczne? Wydaje mi się, że błędy można wychwycić tylko fizycznie obserwując działanie maszyny.
A może po prostu nie rozumiem, jak powinny działać testy jednostkowe?
( Jeśli to ma znaczenie, oto kod , jest napisany w C ++, a ja uczestniczę we FRC )
źródło
Mogę wymyślić kilka rzeczy, które musisz rozważyć. Pierwszym z nich jest uczynienie warstwy dostępu sprzętowego tak cienką, jak to tylko możliwe, nawet jeśli oznacza to utworzenie dla niej podstawowej warstwy otoki. Daje to kilka zalet. Pierwszy polega na tym, że pozwala on odizolować specyficzne dla sprzętu zachowania twojego kodu od samego dostępu do sprzętu, co oznacza, że możesz przetestować wszystko aż do samego dołu sprzętu bez konieczności uzyskiwania dostępu do samego sprzętu.
Na przykład, jeśli musisz zaprojektować protokół sygnalizacyjny oparty na I2C, możesz przetestować, czy Twój kod generuje poprawne sygnały I2C bez konieczności podłączania sprzętu do swoich testów.
W przypadku połączeń z rzeczywistym sprzętem możesz sprawdzić, czy zachowują się poprawnie, wyśmiewając warstwę sprzętową, i właśnie w tym przypadku opłaca się utrzymanie bardzo cienkiej warstwy sprzętowej, ponieważ możesz zredukować próbę do konieczności obsługi tylko minimalnych funkcji wymaganych do faktycznie adresują sprzęt, ale niekoniecznie musisz testować poszczególne sygnały, ponieważ wszystkie sygnały powinny być testowane na wyższym poziomie. Oznacza to, że używasz swojej makiety, aby sprawdzić, czy połączenia są wykonywane z wykorzystaniem określonych metod sprzętowych, które powodują wysyłanie sygnałów do sprzętu. Jeśli potrzebujesz sondować swój sprzęt, twoja próbka musi być w stanie wywoływać zdarzenia lub metody tylko w kodzie, ponieważ ponownie, sygnał zwrotny powinien być obsługiwany na wyższej warstwie.
Zasadniczo pasuje to do tego, co powiedział Oleksi w swojej odpowiedzi , ponieważ zwykle jest więcej pracy, aby wyśmiewać rzeczy na poziomie sprzętowym, jednak nie jest to takie trudne, jeśli trzymasz się możliwie najcieńszej warstwy minimalnego kodu / wywołania, którą możesz zrobić dla sprzęt komputerowy.
Jeśli masz kod, który przejdzie wszystkie testy, nadal będziesz musiał przeprowadzić serię testów ręcznych, aby upewnić się, że wszystko poprawnie skonfigurowałeś w warstwie sprzętowej.
Inną rzeczą, która przychodzi mi na myśl oprócz kpiny i nawarstwiania się, jest zastosowanie praktyki rozwoju w pierwszej kolejności. Zasadniczo kodujesz swoje wymagania jako kryteria testowe i opierasz swoją implementację na testach. Pomoże to zapewnić utrzymanie kodu implementacji na minimalnym poziomie, a jednocześnie upewnić się, że wszystkie przypadki testowe napędzają wysiłki programistyczne. Nie marnując zbyt wiele czasu na inny potencjalnie niekrytyczny kod, który może Cię kusić „tylko dlatego, że”, test najpierw pomaga zachować koncentrację i ułatwi zmianę kodu podczas debugowania, podobnie jak użycie swoich testów jednostkowych i próbnych. Debugowanie błędów oprogramowania przez sprzęt jest niezwykle skomplikowane i pochłania dużą ilość czasu, który lepiej byłoby poświęcić na inne zadania.
źródło
Mogę powiedzieć, jak to robią w symulatorach lotu
Po pierwsze, dostaniesz tylko połowę odpowiedzi, jeśli zadasz to pytanie tylko programistom, więc prawdopodobnie powinieneś zamieścić to na http://electronics.stackexchange.com, gdy jesteś przy nim.
Nie robiłem żadnej roboty z robotami, ale spędziłem 5 lat na tworzeniu sprzętu na symulatorach lotu, dzięki czemu mogę powiedzieć, jak działa ich architektura.
Warstwa sprzętowa jest głupia
Zawiera podstawowy interfejs, w którym można regulować proste wartości wejściowe / wyjściowe i ustawiać punkty przerwania interpolacji dla sygnałów analogowych. Kiedy pracujesz ze „świeżym” sprzętem, wszystko będzie działało zgodnie z oczekiwaniami, z niewielką lub żadną kalibracją, ale z czasem części ulegną zużyciu mechanicznemu i będą musiały zostać wyregulowane.
Kalibracja jest prostą tabelą zawierającą przekroje w zakresie od wartości min / maks. Aby zmierzyć na nich wejście, zwykle stosuje się serwo (np. Potencjometr liniowy, przetwornik, akcelerometry itp.). Lub w przypadku oprzyrządowania, po prostu wizualnie oceniasz dokładność i dostosowujesz do momentu skalibrowania.
Warstwa oprogramowania jest odwrotna
Wszystko jest złożone i powiązane ze sobą, dlatego ważne jest, aby wyodrębnić niektóre zmienne w celu przetestowania funkcjonalności. Wymyślanie scenariuszy związanych z bólem głowy nie jest konieczne, ponieważ o wiele łatwiej jest uruchomić realistyczne scenariusze, w których można gromadzić dane. Po uruchomieniu testów zasadniczo mierzysz przechowywane dane w porównaniu z bieżącym wyjściem.
W symulatorze lotów jest to określane jako QTG (Przewodnik po testach kwalifikacyjnych). U ich podstaw wykreślane są dane na siatce 2D, gdzie jeden wymiar to czas, a drugi to wynik.
Wierzcie lub nie, to esencja tego, jak opracowują modele. Prawdziwy samolot jest wyposażony w masę czujników i lata się wokół niego, wykonując kontrolowane scenariusze. Ponieważ wszystkie elementy sterujące mogą być sterowane bez interakcji człowieka, testy są uruchamiane (tzn. Sama karta leci) przez komputer i dane są porównywane.
Mimo że robotyka jest tworzona na znacznie inną skalę, zasady są takie same. Tradycyjne podejście polega na całkowitym oddzieleniu warstw sprzętowych i programowych, aby można je było przetestować osobno. Dane sprzętowe są gromadzone przez serwomechanizmy i ustawiane przez niezależny interfejs. Wejście oprogramowania można ustawić / odczytać, niezależnie mierząc i porównując sygnalizację, która w innym przypadku trafiłaby do sprzętu i wykreślając ją względem znanych „dobrych” danych.
Same testy niekoniecznie muszą być skomplikowane, o ile wyniki są przewidywalne, mierzalne i odtwarzalne.
źródło
Jak już wspomniano, wykpij i wytrzyj części sprzętowe. Na przykład, jeśli masz interfejs do robota, możesz dziedziczyć z tego interfejsu, a następnie wykonać proste jego implementacje. Następnie możesz przetestować, czy implementacja kodu pośredniczącego została wywołana zgodnie z oczekiwaniami. Jeśli jest to oczekiwane funkcje lub oczekiwane parametry.
źródło