Jak przetestować generowanie wykresów?

1

Mam teraz prostą klasę javową, która na podstawie danych liczbowych generuje wykresy uzywając Image oraz Graphics2D (czyli metody typu drawString, fillRectangle itd...).
Jak to przetestować? Nie będę przecież generował obrazka a potem OCRem sprawdzał czy jest tytuł w odpowiednim miejscu.
Jedyne co mi przychodzi do głowy to te niskopoziomowe operacje wydzielić do osobnej klasy i w testach sprawdzać wywołania.
Jakieś inne pomysły?

2

Jeżeli rzeczywiście chcesz testować obrazki to są do tego gotowe biblioteki np https://github.com/romankh3/image-comparison
https://github.com/toninofox/resemble-java

3
Łukasz Wojtów napisał(a):

Jedyne co mi przychodzi do głowy to te niskopoziomowe operacje wydzielić do osobnej klasy i w testach sprawdzać wywołania.

W ten sposób twoje testy będą uzależnione od implementacji, czyli zrobisz takie "tautological tests", które nic nie sprawdzają, a jedynie to, czy implementacja jest zaimplementowana tak, jak była implementowana.

Trochę bez sensu w sytuacji, kiedy implementacja nie powinna mieć znaczenia (chodzi w końcu o to, czy wykresy są poprawnie generowane, a nie to, jakimi wywołaniami). Już lepiej sprawdzić jakimiś narzędziami, czy generowane obrazki są podobne (jak przedmówca wspomniał).

3

Zastanów się co faktycznie chcesz przetestować.

  • chcesz napisać pod prezentacje swoich danych (która po prostu tak się złożyło że używa wykresów)?
  • czy chcesz przetestować konkretnie te wykresy, bo np robisz edytor wykresów?

Jeśli to pierwsze, to dobrym wzorcem byłby Humble Object, no i ja bym chyba napisał jeden test który w jakiś sposób sprawdza render - ale to powinien być max. jeden - reszta logiki prezentacji liczb powinna być właśnie w humble object.

Jeśli to drugie, to chyba wszystkie testy powinny parsować wykres z obrazka.

Tak na prawdę problem który masz, jest bardzo popularny - ciężko jest przetestować coś co jest na granicy systemu - jak obrazek, który ma ładnie wyglądać dla ludzi.

3

To jest jedna z tych rzeczy, których podstawową własnością jest to, czy subiektywnie dobrze pasują ludziom, więc niestety w praktyce najlepiej się to testuje ludźmi. Na pewno testy manualne będą niezbędnym składnikiem tutaj — tylko człowiek będzie w stanie stwierdzić, czy wykres ma logiczny sens, czy jest czytelny, czy jest ładny.

Tym niemniej można to trochę przemacać naokoło. Oprócz wyżej wymienionych metod, jako wielki piewca testów własności, proponuję dorzucić właśnie je. Na pewno da się stwierdzić odgórnie, jakie ogólne cechy musi mieć każdy poprawny wykres — na przykład nie być większy niż xxx × yyy pikseli; nie mieć więcej, niż 4 MB; mieć wysoki kontrast; mieć nie za wiele, ale i nie za mało krawędzi. Potem, w ramach wykrywania i naprawiania wykrytych ręcznie błędów, będziecie pewnie mieli kolejne pomysły na takie ogólne własności do testów.

1

Gdybym miał to testować to raczej w ten sposób, że robię adapter tych funkcji rysujących i tego obiektu nie testuję. Natomiast w testach logiki budowania wykresu po prostu mockuję ten adapter i tyle. Dużo zabawy z tym, ale innego pomysłu (niż ewentualnie nauczenie jakiegoś MLa/sieci neuronowej oceniania screenów) chyba nie mam :)

0

Większość aplikacji biurowych jest w stanie generować wykres(y) na podstawie danych wejściowych.

0

Inaczej bym do tego podszedł jeśli to byłaby biblioteka do generowania wykresów - wtedy faktycznie może bawiłbym się w OCR, biblioteki do porównywania obrazków itp.
Ale jeśli to tylko jedna mało znacząca funkcja większej aplikacji to przetestowałbym to co się da niewizualnie i po prostu wygenerował wykres, zapisał go jako wzorzec w png i napisał jeden test który sprawdzi 1:1 czy wygenerowany plik wykresu zapisanego jako .png jest identyczny.
To betonuje co prawda wygląd wykresu i wymaga żeby wygenerować nowy wzorzec za każdym razem gdy chcemy zmienić font, czy przesunąć lekko tekst ale to zapewne nie zdarzy się zbyt często a zyskujemy większą pewność siebie przed zmianami w kodzie, refaktoringiem i updatem zależności.

Porównywanie obrazków wyżej wymienionymi bibliotekami które dają sobie ustalić margines błędu może moim zdaniem dawać false positive - jeśli jedna cyferka na wykresie się nie będzie zgadzać (na przykład zaokrąglenie w złą stronę) to obrazek nadal może być w 99.999% identyczny a mieć kluczowe znaczenie. Myślę że w tym przypadku obrazki powinny być w 100% identyczne bez żadnego marginesu błędu.

0

Libkę (pierwszą) da się skonfigurować tak żeby testował 1:1 z tego co na szybko sprawdziłem, no ale wtedy to można pixel po pikselu.

0

Przychodzą mi dwie stuczki do głowy, w testach używasz specyficznych kolorów, w takim wypadku, jeśli jesteś wstanie wyeksportować widok, do bitmapy, dość łatwo zrobisz OCR.
Drugi myk, to przekazanie to dodanie do podstawowych kształtów opcji visibility, a potem tak ich sprytne wysterowanie, że cała warstawa znika w teście. I mozna każdy screen podzieli na kilka klatek.
łacząc te dwie techniki, stosunkowo łatwo mozesz napisać kod, który sprawdza, czy wyświetla się siatka, czy wykres przykrywa siatkę i skale itp. Robisz cos obiektywnie potrzebnego i dostajesz dobre narzędzie do debiutowania.

Implementacyjnie powinno być to proste, w wysoko poziomowych obiektach wystarczy trzymać kolor i vidoczność w jakiś wraperze. Dependecy injection, fabryka itd. i możesz jednym metodą przełączać całe grupy.

@Althorion To dobry pomysł, każdy taki wykres powinien dać sie z mapować, na "Dane wejsciowe", "entyki do wyrenderowania" i mozna kobinować w tym zakresie pisać testy, bo masz obiekty, a nie OCR. ale nie zrobisz tak wystkiego.

0
_flamingAccount napisał(a):

Przychodzą mi dwie stuczki do głowy, w testach używasz specyficznych kolorów, w takim wypadku, jeśli jesteś wstanie wyeksportować widok, do bitmapy, dość łatwo zrobisz OCR.
Drugi myk, to przekazanie to dodanie do podstawowych kształtów opcji visibility, a potem tak ich sprytne wysterowanie, że cała warstawa znika w teście. I mozna każdy screen podzieli na kilka klatek.
łacząc te dwie techniki, stosunkowo łatwo mozesz napisać kod, który sprawdza, czy wyświetla się siatka, czy wykres przykrywa siatkę i skale itp. Robisz cos obiektywnie potrzebnego i dostajesz dobre narzędzie do debiutowania.

Implementacyjnie powinno być to proste, w wysoko poziomowych obiektach wystarczy trzymać kolor i vidoczność w jakiś wraperze. Dependecy injection, fabryka itd. i możesz jednym metodą przełączać całe grupy.

Tylko zastanów się po co miałbyś to robić? Testy mają Ci pomagać utrzymać i refaktorować kod.

Test napisany w taki sposób jaki przedstawiłeś nie spełnia tej funkcji.

Jedyny sensowny test jaki mi przychodzi do głowy musiałby wyglądać jakoś tak:

void test() {
  Chart chart = new Chart();
  assertTrue(looksGood(chart));
}

Tylko że funkcje looksGood() raczej ciężko napisać 😄

0

Tylko zastanów się po co miałbyś to robić? Testy mają Ci pomagać utrzymać i refaktorować kod.

Test napisany w taki sposób jaki przedstawiłeś nie spełnia tej funkcji.

To? czym jest to? z tego co pamiętam mam 3 przykłady i ich zestawianie razem. Taki? Jaki? Dlaczego nie spelniaja tej fukcji.

Merytorycznie to mamy "nie bo nie", oraz "nie umiem testować czy ladnie wyglada".

W zależności od poziomu skomplikowania spokojnie można na przypadki przegowe. A nawet jeżeli sie nie da, to bardzo usprawinic, proces "czy ładnie wygląda pana okiem" całą serią filtrów.

0
_flamingAccount napisał(a):

Tylko zastanów się po co miałbyś to robić? Testy mają Ci pomagać utrzymać i refaktorować kod.

Test napisany w taki sposób jaki przedstawiłeś nie spełnia tej funkcji.

To? czym jest to? z tego co pamiętam mam 3 przykłady i ich zestawianie razem. Taki? Jaki? Dlaczego nie spelniaja tej fukcji.

Merytorycznie to mamy "nie bo nie", oraz "nie umiem testować czy ladnie wyglada".

W zależności od poziomu skomplikowania spokojnie można na przypadki przegowe. A nawet jeżeli sie nie da, to bardzo usprawinic, proces "czy ładnie wygląda pana okiem" całą serią filtrów.

UI się testuje bardzo trudno. Czaesm się da, ale niestety w przypadku takich wykresów generowanych na obrazkach jestem raczej niemalże pewny że się nie da.

No bo tak:

  • albo ten testy będzie bardzo czuły, tak że dowolny refaktor sprawi że test nie przejdzie - czyli nie ważne czy coś zepsujesz czy nie, test failuje
  • albo będzie obojęty, i nawet jak zepsujesz zachowanie wykresu to test przejdzie - czyli nie ważne czy coś zepsujesz czy nie, to test przechodzi

Czyli dostaniesz test który albo zawsze failuje, albo zawsze przechodzi. Tylko po co Ci taki test?

Jedynym wyjściem żeby to zrobić, to albo manualny test - człowiek na to patrzy i stwierdza czy jest okej czy nie; albo jakiś bardzo mądry AI który potrafi stwierdzić czy wykres nadaje się do pokazania użytkownikom czy nie.

0

Jeżeli twoim celem jest ocenienie czy holistycznie wszystko działa dobrze to jest to bardzo trudne. Jeżeli zaczniesz zadawać sobie inne pytania, to pojawia sie problemy które da sie przetestować.

Czy jest cos co da się przetestować?

Przy odpowiedniej ilości dyscypliny, można odseparować model danych od ich reprezentacji graficznej. Takie modele można bez problemu przetestować unit testami, a to pozwoliło by napisać testy na rzeczy takie jak rotate, translate itp. czy generowanie bardziej skomplikowanych struktur.
Takie podejście sprawdza błedy w "naszym kodzie", pomagając "refaktorować i utrzymywać kod". To nie zaprzeczalne.

Można też testować konkretne przypadki:

Autor nie napisał jak skomplikowany jest jego program, a sky is the limit w przypadku takiego softu, ale założymy ze chcemy przetestować generowania kratownic współrzędnych. Czy można napisać kod który sprawdza czy ładnie wyglada? Cieżko.
Czy można napisać kod który sprawdza czy zaczyna się w 0,0, mozna. Czy można napisać kod, który sprawdza dystans miedzy limimi, i czy dobrze oddaja wartości i nie sa przesuniete? mozna. Czy mozna napisać kod, który sprawdza czy jest dobra liczba lini w zależności od skali? mozna.

Mozna napisać kod który sprawdza czy działa akalowanie , czy działa przekazywanie kolorów przez wszystkie warstwy. Czy elementy są widoczne.

Pod wygląda dobrze kryje sie cała masa technikaliów które mozna sprawdzić, a narzedzia podbne dotych opisanych w poście 1, pozwoliły by uczynic sprawdzenia odpowiednio mało pracochłonnymi.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.