Ładne kończenie switcha

49 views
Skip to first unread message

Adam Michalik

unread,
Jul 4, 2011, 4:03:22 AM7/4/11
to Warszawa Java User Group (Warszawa JUG)
Witajcie! Miewam czasem taki dylemat - jak ładnie zakończyć switcha.
Załóżmy, że mamy taki przypadek:

public class Test {

public static enum MyEnum {
ONE, TWO, THREE;
}

public void foo(MyEnum e) {
switch (e) {
case ONE:
break;
case TWO:
break;
case THREE:
break;
default:
break; // ???
}
}

}

Co uważacie za najlepsze do umieszczenia w default? Opcje widzę
następujące:
- nie pisać default (wszystkie elementy enuma są obsłużone) - ale co,
jeśli ktoś kiedyś dopisze kolejny element enuma?
- napisać default: assert false : "Oops!"; - ale asercje zazwyczaj
mamy wyłączone
- rzucić wyjątek. Jaki? AssertionError? IllegalArgumentException?

Analogiczny przypadek dotyczy inta:

public void bar(int i) {
validate(i);
switch (i) {
case 0:
break;
case 1:
break;
case 2:
break;
default:
break;
}
}

Zakładamy, że validate() waliduje i tak, że rzuca wyjątek jeśli i<>0,
1, 2. Ale co jeśli validate jednak nie do końca działa? ;)

Jakie rozwiązanie stosujecie? Ja do tej pory rzucałem AssertionError,
czasem IllegalArgumentException, ale chciałbym robić to z pełnym
przekonaniem ;)

Bartek Kuczyński

unread,
Jul 4, 2011, 4:09:52 AM7/4/11
to warsza...@googlegroups.com
W przypadku enumów wyjątek. Jak ktoś coś dopisze po powinno nie
przejść testów. Chyba, że nowy enum jest odpowiednio rozpropagowany.
W przypadku intów zazwyczaj null object, albo nie robię nic i
użytkownik dostaje NPE. W ogóle switch to brzydkie rozwiązanie.

enum Switch implements Action{
ONE{
void doAction(){}
}
TWO{
void doAction(){}
}
//...
}

Potem można zamiast switcha wywołać metodę doAction i jak nawet ktoś
coś dopisze to będzie musiał ta metodę napisać.

Z intów w switchach już od dawna nie korzystam.

Pozdrawiam
Bartek "Koziołek" Kuczyński
http://koziolekweb.pl
Lepiej pomyśleć dwa razy i zacząć programować
niż dwa razy programować i potem zacząć myśleć
 \     /
 ~00~
  \_/
   |||

> --
> Otrzymujesz tę wiadomość, ponieważ subskrybujesz grupę dyskusyjną Google o nazwie "Warszawa Java User Group (Warszawa JUG)".
>
> Aby zamieszczać posty w tej grupie, wyślij e-mail na adres warsza...@googlegroups.com.
> Aby anulować subskrypcję tej grupy, wyślij e-mail na adres warszawa-jug...@googlegroups.com.
> Aby uzyskać więcej informacji, odwiedź tę grupę pod adresem http://groups.google.com/group/warszawa-jug?hl=pl.
>
>

Jakub Nabrdalik

unread,
Jul 4, 2011, 4:34:15 AM7/4/11
to warsza...@googlegroups.com, Adam Michalik
W dniu 04.07.2011 10:03, Adam Michalik pisze:

> Jakie rozwiązanie stosujecie? Ja do tej pory rzucałem AssertionError,
> czasem IllegalArgumentException, ale chciałbym robić to z pełnym
> przekonaniem ;)

Bartek ładnie napisał, że powinien nie przejść testów, co pewnie masz
zaimplementowe w validate(i).

Ze switcha nie korzystam (w webie w praktyce zawsze user podejmuje
decyzje, więc if'y są niepotrzebne, w integracji wolę obiektowość i
enumy) tym nie mniej, ponieważ lubię defensive programming, w
sytuacjach, które nie powinny wystąpić rzucam
ThingsThatShouldNotBeException. Jak wybuchnie, od razu wiadomo, że chaos
wkroczył do projektu ;)

NPE nie lubię.


--
Jakub Nabrdalik
http://solidcraft.eu

Irek Matysiewicz

unread,
Jul 4, 2011, 4:49:18 AM7/4/11
to warsza...@googlegroups.com
W dniu 4 lipca 2011 10:09 użytkownik Bartek Kuczyński <bjkuc...@gmail.com> napisał:
W przypadku enumów wyjątek. Jak ktoś coś dopisze po powinno nie
przejść testów. Chyba, że nowy enum jest odpowiednio rozpropagowany.
W przypadku intów zazwyczaj null object, albo nie robię nic i
użytkownik dostaje NPE. W ogóle switch to brzydkie rozwiązanie.

enum Switch implements Action{
  ONE{
    void doAction(){}
  }
 TWO{
    void doAction(){}
  }
//...
}

Potem można zamiast switcha wywołać metodę doAction i jak nawet ktoś
coś dopisze to będzie musiał ta metodę napisać.


To po prostu nic innego jak wzorzec strategia opakowany w enuma, tak jak w ubiegłym tygodniu na którymś poście pokazał Lasu. :-)


Ja bym do tej paczki sposobów dorzucił jeszcze inne:

- wzorzec Wizytator. Ten przykład z enumem na wizytatora można przepisać tak:
switch.accept(new SwitchVisitor() {
     void one(...) { ... }
     void two(...) { ... }
     ...
});
Jeśli będzie brakowało obsługi któregoś z przypadków, kompilator sypnie błędem. Ja nie przepadam za tym wzorcem, ale wiem że są tacy co go lubią.

- Pod Eclipsem można doinstalować plugin do Checkstyle, a Checkstyle m.in. potrafi krzyczeć gdy brakuje  jakiegoś case'a w enumach. Pewnie w innych IDE też da się coś takiego skonfigurować, choć nigdy nie próbowałem.


No ale ogólnie rzecz biorąc zgadzam się z wami w 100%: testy, throw cośtam, assert cośtam czy nawet assert false to wg mnie podstawa. Testami wykryjemy o wiele więcej problemów niż kompilatorem, nie wspominając że np. w takim JavaScripcie kompilatora nie ma, a jakieś testy, throwy czy asercje zawsze można napisać chyba w każdym języku.

Bartek Kuczyński

unread,
Jul 4, 2011, 4:52:29 AM7/4/11
to warsza...@googlegroups.com
Irek, ja się silnie inspirowałem ostatnia dyskusją w tym przypadku.
Twórcze rozwinięcie strategii w enumy to od dłuższego już czasu moje
hobby przypisaniu UI.


Pozdrawiam
Bartek "Koziołek" Kuczyński
http://koziolekweb.pl
Lepiej pomyśleć dwa razy i zacząć programować
niż dwa razy programować i potem zacząć myśleć
 \     /
 ~00~
  \_/
   |||

W dniu 4 lipca 2011 10:49 użytkownik Irek Matysiewicz
<iir...@gmail.com> napisał:

Vitaliy Oliynyk

unread,
Jul 5, 2011, 5:04:10 AM7/5/11
to warsza...@googlegroups.com
Można to jeszcze bardziej uprościć nie tworząc osobnego interfejsu Action:

enum Switch {
  ONE{
    void doAction(){}
  },

 TWO{
    void doAction(){}
  };
  
  public abstract void doAction();
}

Niestety NetBeans 7 ne proponuje stosownej podpowiedzi jeżeli nie zaimplementujemy metody abstrakcyjnej w odróznieniu od Idea 10.5.1, 9.4 oraz Eclipse 3.6.2  


W dniu 4 lipca 2011 10:09 użytkownik Bartek Kuczyński <bjkuc...@gmail.com> napisał:

Jacek Laskowski

unread,
Jul 5, 2011, 5:43:31 AM7/5/11
to warsza...@googlegroups.com
2011/7/5 Vitaliy Oliynyk <xao...@gmail.com>:

> Można to jeszcze bardziej uprościć nie tworząc osobnego interfejsu Action:
> enum Switch {
>   ONE{
>     void doAction(){}
>   },
>  TWO{
>     void doAction(){}
>   };
>
>   public abstract void doAction();

A co myślisz/-cie o dodaniu implementacji do doAction()? Warte
zachodu? (na chwilę obecną widzę zaletę, braku konieczności jej
tworzenia w enumach).

Jacek

--
Jacek Laskowski
Java EE, functional languages and IBM WebSphere - http://blog.japila.pl
Warszawa JUG conference = Confitura (formerly Javarsovia) :: http://confitura.pl

Bartek Kuczyński

unread,
Jul 5, 2011, 5:48:03 AM7/5/11
to warsza...@googlegroups.com
Jacek, zawsze doAction() można potraktować jako metodę szablonową i w
poszczególnych wartościach zaimplementować mniejsze metody. Swoją
drogą dobry temat na rozważania wieczorne.

Pozdrawiam
Bartek "Koziołek" Kuczyński
http://koziolekweb.pl
Lepiej pomyśleć dwa razy i zacząć programować
niż dwa razy programować i potem zacząć myśleć
 \     /
 ~00~
  \_/
   |||

Sławek Sobótka

unread,
Jul 6, 2011, 9:09:35 AM7/6/11
to Warszawa Java User Group (Warszawa JUG)
Każdy pattern ma swój kontekst, w którym jest stosowalny. Poza tym
kontekstem będzie już nieodpowiedni lub wręcz szkodliwy.

I tak:

Enum jako strategia jest dobry dopóki:
- nie zaczynamy dodawać do niego coraz więcej metod - wówczas staje
się "boską klasą" (przypadek gdy od tego enuma zależy wiele miejsc w
kodzie)
- nie zaczyna posiadać złych zależności - np do serwisów, które coś
tam jeszcze robią i koniec końców jeszcze grzebią w bazie:)

Enum jako dający się wizytować obiekt (rozwiązanie Irka) rozwiązuje
powyższe problemy:
- nowe zachowania to implementacje nowych wizytatorów - enum się nie
rozrasta
- ciężar zależności spada na wizytatory (nie wizytatorów - uprzedzając
uwagi lang-nazi;)

Ale oba te rozwiązania tracą sens gdy enum jest np. obiektem
transferowanym na inne poziomy (w sensie Tier a nie Layer), np na
zdalnego klienta. Wówczas ciągnie za sobą zależności do klas
implementacji usług servera tak jak ciągnie się za gaciami smrodek;)


Sławek Sobótka
http://art-of-software.blogspot.com
http://ssepp.pl

Bartek Kuczyński

unread,
Jul 6, 2011, 9:15:16 AM7/6/11
to warsza...@googlegroups.com
Sławek dlatego też jak ze wszystkim tak i z enumami trzeba delikatnie.

Swoją drogą należy też pamiętać, że dla końcowego odbiorcy naszego
kodu jedynym wyznacznikiem jakości jest poprawne działanie. Jeżeli
zatem za bardzo namieszamy w kodzie to będzie głównie nasz problem.

Pozdrawiam
Bartek "Koziołek" Kuczyński
http://koziolekweb.pl
Lepiej pomyśleć dwa razy i zacząć programować
niż dwa razy programować i potem zacząć myśleć
 \     /
 ~00~
  \_/
   |||

Lasu

unread,
Jul 7, 2011, 3:44:53 AM7/7/11
to Warszawa Java User Group (Warszawa JUG)
On 4 Lip, 10:03, Adam Michalik <a...@o2.pl> wrote:
> Witajcie! Miewam czasem taki dylemat - jak ładnie zakończyć switcha.
> Załóżmy, że mamy taki przypadek:
>
> public class Test {
>
>     public static enum MyEnum {
>         ONE, TWO, THREE;
>     }
>
>     public void foo(MyEnum e) {
>         switch (e) {
>             case ONE:
>                 break;
>             case TWO:
>                 break;
>             case THREE:
>                 break;
>             default:
>                 break; // ???
>         }
>     }
>
> }
>

Ave
Pamiętaj, że wyjątek zależy od kontekstu więc zastosowanie czegoś
poza IllegalArgumentException może być jak najbardziej ok.

Uwaga:
Dla małych enumów jest to jak najbardziej ok / dla większych typu:


public static enum MyEnum {
Element001,Element002, .... Element050;
}

public void foo(MyEnum e) {
switch (e) {
case Element001:
...
break;
case Element002:
...
break;
case Element025:
case ....
case Element050:
/* just */ break;
default:
throw new IllegalArgumentException();
}
}


warto jest zmienić miejsce walidowania zmienności enum-a:


final public class Test {

/**
* Matter for:
* @see #foo(MyEnum)
*/
static /* ensure proper enum*/ {
final MyEnum[] suported = new MyEnum[]{ MyEnum.Element001, ...
MyEnum.Element050};
//TODO exception if supported have different elements than
MyEnum.values()
}

public static enum MyEnum {
Element001,Element002, .... Element050;
}

public void foo(MyEnum e) {
switch (e) {
case Element001:
...
break;
case Element002:
...
break;
default /* by virtue of static block validation */:
break;
}
}

}


Jeśli chodzi o metody w enumie / to ja osobiście zastanawiam się czy:
> 'coś' reprezentowane przez element enuma ma charakter statyczny w rzeczywistości - jeśli nie to może warto zastosować inną konstrukcję - a problem metod rozwiąże się sam.
> czy metoda wynika z bezpośrednio z tego co reprezentuje sobą enum w naszym mniemaniu ma charakter logiki tak jak:
enum LogicOperations{
Or{...},//
And{...},//
;
...
}
powinien mieć min. metodę:
abstract boolean count (boolean... values);
co pozwoli spójnie traktować enuma nawet gdy dodamy kiedyś Xor itp.

Dla uproszczenia można zastosować zasadę:
Przy pierwszym zduplikowaniu logiki dodajemy ją co najmniej do JavaDoc-
a jako @see co przy obecnych narzędziach nie jest wielkim problemem
przy odrobinie samozaparcia.


--
Pozdrowionka
Marek Kozieł
http://lasu2string.blogspot.com/

Irek Matysiewicz

unread,
Jul 7, 2011, 4:26:34 AM7/7/11
to warsza...@googlegroups.com

Jak masz enuma z 50 elementami to na 99% masz coś nie tak w kodzie. :-)
Przypomina mi to WinAPI, gdzie np. do obsługi eventów GUI używa się jednej z kilkuset wartości typu WM_CLOSE, WM_CUT, WM_COPY, WM_PASTE, TVM_DELETEITEM, BM_SETMESSAGE, .... Jest tego tak dużo, że w samej dokumentacji musieli porozdzielać to na sekcje i podsekcje: http://msdn.microsoft.com/en-us/library/ms644927%28v=vs.85%29.aspx
Kto próbował swoich sił w winapi wie jakie jest to toporne. Te enumy pewnie po prostu powinny tu stać się klasami (tak jak np. paskudne stałe z WinAPI stały się klasami WindowEvent czy MouseEvent w Swingu).
 


warto jest zmienić miejsce walidowania zmienności enum-a:


final public class Test {

 /**
  * Matter for:
  * @see #foo(MyEnum)
  */
 static /* ensure proper enum*/ {
     final MyEnum[] suported = new MyEnum[]{ MyEnum.Element001, ...
MyEnum.Element050};
     //TODO exception if supported have different elements than
MyEnum.values()
  }

Fajnie by było tak łatwo rozwiązać ten problem, ale niestety tak nie jest: ten test zawiera copy&paste kodu z enuma (bierzesz wszystko z enuma i przenosisz do testu wewnątrz tablicy {...}). Testy, które są lustrzanym odbiciem kodu niewiele testują ('nie widzą' szerszego kontekstu) i są trudne w utrzymaniu (nawet najmniejsza nieistotna zmiana w kodzie wymaga zmian w teście). Problem ten jest szczególnie widoczny gdy za mocno używa się mokowania (EasyMock, PowerMock, ...). Fowler w swojej książce o testach nazywa to "fragile tests" czy jakoś tak. Ja bym napisał testy do metod/klas, które używają tego enuma i błędy np. z nieobsłużeniem jakiegoś przypadku powinny same wyskoczyć jeśli te testy do tych metod są sensowne. Dodatkowo jak używamy tego podejścia z default: throw new ... to kod dodatkowo 'testuje się' podczas normalnego wykonania, gdy użytkownik wyklikał coś takiego co nam nawet nie przyszło do głowy pisząc testy.

Jacek Laskowski

unread,
Jul 7, 2011, 4:28:36 AM7/7/11
to warsza...@googlegroups.com
2011/7/7 Lasu <develo...@gmail.com>:

> Uwaga:
> Dla małych enumów jest to jak najbardziej ok / dla większych typu:
>
>
> public static enum MyEnum {
>         Element001,Element002, .... Element050;
>     }
>
>  public void foo(MyEnum e) {
>         switch (e) {
>             case Element001:
>                    ...
>                 break;
>             case Element002:
>                    ...
>                 break;
>             case Element025:
>             case ....
>             case Element050:
>                 /* just */ break;
>             default:
>                throw new IllegalArgumentException();
>         }
>     }

Śledząc tę dyskusję i próbując zmagać się z moim problemem, który
opisałem w innym wątku, mam nieodparte wrażenie, że jedynym
uzasadnieniem w/w podejścia mogłaby być jedynie sytuacja, w której nie
mamy możliwości zmiany enuma. Jeśli mamy, dodałbym metodę do enuma i
zrzuciłbym temat decyzji, co robić z danym enumem na jvm.

Lasu

unread,
Jul 7, 2011, 6:24:34 AM7/7/11
to Warszawa Java User Group (Warszawa JUG)
Ave,

On 7 Lip, 10:26, Irek Matysiewicz <iir...@gmail.com> wrote:
> Jak masz enuma z 50 elementami to na 99% masz coś nie tak w kodzie. :-)
Jeśli w rzeczywistości występuje 50 elementów to czemu enum nie miał
by ich tyle też zawierać?

> Przypomina mi to WinAPI, gdzie np. do obsługi eventów GUI używa się jednej z
> kilkuset wartości typu WM_CLOSE, WM_CUT, WM_COPY, WM_PASTE, TVM_DELETEITEM,
> BM_SETMESSAGE, .... Jest tego tak dużo, że w samej dokumentacji musieli
> porozdzielać to na sekcje i podsekcje:http://msdn.microsoft.com/en-us/library/ms644927%28v=vs.85%29.aspx
> Kto próbował swoich sił w winapi wie jakie jest to toporne. Te enumy pewnie
> po prostu powinny tu stać się klasami (tak jak np. paskudne stałe z WinAPI
> stały się klasami WindowEvent czy MouseEvent w Swingu).
Pytanie czy enum reprezentuje jedną spójną całość.



>
> Fajnie by było tak łatwo rozwiązać ten problem, ale niestety tak nie jest:
> ten test zawiera copy&paste kodu z enuma (bierzesz wszystko z enuma i
> przenosisz do testu wewnątrz tablicy {...}). Testy, które są lustrzanym
> odbiciem kodu niewiele testują ('nie widzą' szerszego kontekstu) i są trudne
> w utrzymaniu (nawet najmniejsza nieistotna zmiana w kodzie wymaga zmian w
> teście).

Ja uważam to za plus(konieczność) / gdyż trzeba uważać żeby testy nie
były sprytniejsze od nas ;P

Także dziwi mnie logika według której nie można dodawać za dużo metod
do enuma za to można ignorować przy modyfikacji enuma metody bazujące
na liczbie elementów w enumie.
Moim zdaniem takie postępowanie jest usprawiedliwione tylko jeśli enum
odpowiada za tą logikę - a co za tym idzie może być przetestowany.

> Problem ten jest szczególnie widoczny gdy za mocno używa się
> mokowania (EasyMock, PowerMock, ...).
Ja się odnoszę jedynie do czystej Javy - ale to oczywiste, że każdy
dodatek chachmęcący w kodzie wymaga zwiększenia nakładu na prace
programistyczne.
Wtedy blok statyczny można zmienić na metodę validującą - które może
być re-używalna w ramach klasy.


> Fowler w swojej książce o testach
> nazywa to "fragile tests" czy jakoś tak. Ja bym napisał testy do metod/klas,
> które używają tego enuma i błędy np. z nieobsłużeniem jakiegoś przypadku
> powinny same wyskoczyć jeśli te testy do tych metod są sensowne.
A co jeśli nie są?
Mądry programista to taki który wie, że może się pomylić (także w
testach).


> Dodatkowo
> jak używamy tego podejścia z default: throw new ... to kod dodatkowo
> 'testuje się' podczas normalnego wykonania, gdy użytkownik wyklikał coś
> takiego co nam nawet nie przyszło do głowy pisząc testy.
Dokładnie - Właśnie to samo ma zapewnić blok statyczny.
Zmieni się enum - rozjedzie się zawartość tablicy z .values()



Wyobraźmy sobie, że mamy 50 elementów które kwalifikują się na enuma /
jakie rozwiązanie zastosować?

1.
Jak łatwo będzie wygenerować na podstawie enuma kod 50 klas ?
Jak łatwo będzie wygenerować na podstawie 50 klas wygenerować enuma ?
2.
Enum dosyć mocno wymusza jednolitość.
3.
Hurtowa zmiana konstruktora jest dużo łatwiejsza w enumie
4.
Nowy pracownik od razu ma pełny obraz wszystkich przypadków które mogą
się zdarzyć.
5.
Łatwiej przejrzeć sporego enuma niż 50 klas.
6.
Co lepiej wygląda 500 razy w kodzie:
new ElementX()
> (musimy się zastanawiać czy ma znaczenie czy przekażemy nową instancję/czy obiekt jest zmienny/...)
czy
ElementX.instance
> (nie mamy pewności że ktoś nie zmieni konstruktora na public i będziemy mieli sytuacje mieszaną/ podziedziczy ...)
czy
EnumX.ElementX






On 7 Lip, 10:28, Jacek Laskowski <ja...@japila.pl> wrote:
> 2011/7/7 Lasu <develop4l...@gmail.com>:
> Śledząc tę dyskusję i próbując zmagać się z moim problemem, który
> opisałem w innym wątku, mam nieodparte wrażenie, że jedynym
> uzasadnieniem w/w podejścia mogłaby być jedynie sytuacja, w której nie
> mamy możliwości zmiany enuma. Jeśli mamy, dodałbym metodę do enuma i
> zrzuciłbym temat decyzji, co robić z danym enumem na jvm.
>

Jestem Za

> Jacek
>
> --
> Jacek Laskowski
> Java EE, functional languages and IBM WebSphere -http://blog.japila.pl
> Warszawa JUG conference = Confitura (formerly Javarsovia) ::http://confitura.pl


Irek Matysiewicz

unread,
Jul 7, 2011, 7:21:20 AM7/7/11
to warsza...@googlegroups.com
W dniu 7 lipca 2011 12:24 użytkownik Lasu <develo...@gmail.com> napisał:
Ave,

On 7 Lip, 10:26, Irek Matysiewicz <iir...@gmail.com> wrote:
> Jak masz enuma z 50 elementami to na 99% masz coś nie tak w kodzie. :-)
Jeśli w rzeczywistości występuje 50 elementów to czemu enum nie miał
by ich tyle też zawierać?
Jak zawiera aż 50 elementów, to istnieje ogromne prawdopodobieństwo, że dojdą (albo ujdą) kolejne elementy. Trzymanie tego w jednej klasie łamie Open-Closed Principle (litera 'O' z SOLID), jak dojdzie nowy case to nie dość że będziesz musiał za każdym razem zmieniać tego enuma, i dodatkowo trzeba przejrzeć wszystkie switche używające go. No chyba, że ktoś robi projekt zaliczeniowy na studiach i jest pewien, że to nie będzie się zmieniać. :-)
Ponadto wszystkie te 50 elementów są publiczne. Dobre praktyki mówią by jedna klasa nie miała więcej niż powiedzmy kilkanaście publicznych elementów - poprawia to cohesion i coupling, i ułatwia zrozumienie kodu (elementy są jakby pogrupowane) .

 



>
> Fajnie by było tak łatwo rozwiązać ten problem, ale niestety tak nie jest:
> ten test zawiera copy&paste kodu z enuma (bierzesz wszystko z enuma i
> przenosisz do testu wewnątrz tablicy {...}). Testy, które są lustrzanym
> odbiciem kodu niewiele testują ('nie widzą' szerszego kontekstu) i są trudne
> w utrzymaniu (nawet najmniejsza nieistotna zmiana w kodzie wymaga zmian w
> teście).

Ja uważam to za plus(konieczność) / gdyż trzeba uważać żeby testy nie
były sprytniejsze od nas ;P

Także dziwi mnie logika według której nie można dodawać za dużo metod
do enuma za to można ignorować przy modyfikacji enuma metody bazujące
na liczbie elementów w enumie.

Obawiam się że ciągle mnie nie czaisz: nawet testy jednostkowe nie mogą być za bardzo jednostkowe, np:
- w klasie mamy public static jakieśpole = "cośtam"; jaki sens ma dawanie w teście assertEquals("cośtam", jakieśpole)? - to jest po prostu powielenie fragmentu kodu klasy i nic nie wnosi nowego; ty zrobiłeś mniej więcej to samo: assertArrayEquals({wartości twojego enuma}, TwójEnum.values()) - powieliłeś pole 'values'. To odmiana programowania kopiuj-wklej, do tego trochę zakamuflowana. Po co zostało dodane to pole? - by inne klasy go używały. Przetestuj te inne klasy, to będziesz wiedział że twoje pole jest OK.
- podobnie: mamy metodę a() która woła metodę b(); zwykle niewielki sens ma dodawanie PowerMock.expect(b()); PowerMock.replayAll(); a(); PowerMock.verifyAll()   (znowu duplikacja kodu: b() { a() }), chyba że faktycznie trzeba to zamockować (bo np. b() pisze do bazy, jest elementem publicznego API, czy jest bardzo złożone)

Podsumowając: wg mnie przy pisaniu testów trzeba wejść na odpowiedni poziom złożoności: testowane elementy nie mogą być za proste (np. badanie czy klasa ma takie a takie pole czy taka a taka metoda woła inną metodę - wtedy po prostu duplikujemy kod), ale nie mogą być za złożone (bo np. trudniej będzie ustalić jaka dokładnie była przyczyna nieprzejścia tego a tego testu i testy będą działały wolno).
 
 

Lasu

unread,
Jul 8, 2011, 1:39:40 AM7/8/11
to Warszawa Java User Group (Warszawa JUG)

On 7 Lip, 13:21, Irek Matysiewicz <iir...@gmail.com> wrote:
> W dniu 7 lipca 2011 12:24 użytkownik Lasu <develop4l...@gmail.com> napisał:
> Obawiam się że ciągle mnie nie czaisz: nawet testy jednostkowe nie mogą być
> za bardzo jednostkowe, np:
> - w klasie mamy public static jakieśpole = "cośtam"; jaki sens ma dawanie w
> teście assertEquals("cośtam", jakieśpole)? - to jest po prostu powielenie
> fragmentu kodu klasy i nic nie wnosi nowego; ty zrobiłeś mniej więcej to
> samo: assertArrayEquals({wartości twojego enuma}, TwójEnum.values()) -
> powieliłeś pole 'values'. To odmiana programowania kopiuj-wklej, do tego
> trochę zakamuflowana. Po co zostało dodane to pole? - by inne klasy go
> używały. Przetestuj te inne klasy, to będziesz wiedział że twoje pole jest
> OK.
> - podobnie: mamy metodę a() która woła metodę b(); zwykle niewielki sens ma
> dodawanie PowerMock.expect(b()); PowerMock.replayAll(); a();
> PowerMock.verifyAll()   (znowu duplikacja kodu: b() { a() }), chyba że
> faktycznie trzeba to zamockować (bo np. b() pisze do bazy, jest elementem
> publicznego API, czy jest bardzo złożone)
>
> Podsumowając: wg mnie przy pisaniu testów trzeba wejść na odpowiedni poziom
> złożoności: testowane elementy nie mogą być za proste (np. badanie czy klasa
> ma takie a takie pole czy taka a taka metoda woła inną metodę - wtedy po
> prostu duplikujemy kod),

I tak i nie / tutaj ciężko jest znaleźć złoty środek bo każdy ma inny
styl programowania.
Ja preferuje validatory przy metodach+testy na klasie gdyż przy
zmianach w locie łatwej jest utrzymać spójność projektu.
A testy poza czasem działania aplikacji to tylko integracyjne.

> ale nie mogą być za złożone (bo np. trudniej będzie
> ustalić jaka dokładnie była przyczyna nieprzejścia tego a tego testu i testy
> będą działały wolno).

To też mam odmienne podejście.

Błąd w złożonym teście oznacza, że nie do końca rozumiemy problem bądź
działania kodu - więc według mnie nawet jeśli spędzimy później pół
dnia na analizie to i tak jest to warte zachodu.


Jednak zdaje sobie sprawę, że moje podejście nie wszystkim może
odpowiadać - choćby z faktu, że nie mają takiej presji na szybkość
wprowadzania zmian.

iirekm

unread,
Jul 8, 2011, 3:07:12 AM7/8/11
to warsza...@googlegroups.com
Ehh, ilu developerów tyle podejść do programowania. Jak z kimś pracujesz przez jakiś czas, to nawet bez zaglądania do historii SVN-a z dużym prawdopodobieństwem można powiedzieć kto to napisał. :-)

Marcin Zajączkowski

unread,
Jul 8, 2011, 2:28:01 PM7/8/11
to warsza...@googlegroups.com

Tak, ale teraz jest to trudniejsze. W czasach C (albo lepiej Assemblera)
łatwiej było wypracować swój styl "optymalizacji" :).


Pozdrawiam
Marcin

--
http://solidsoft.wordpress.com/ - Working code is not enough

Bartek Kuczyński

unread,
Jul 8, 2011, 2:34:27 PM7/8/11
to warsza...@googlegroups.com
@Marcin, tu chodzi raczej o pewne rozwiązania na poziomie
wykorzystania kodu. Ja piszę z wykorzystaniem klas wewnętrznych oraz
dużej ilości takich różnych "mikrotypów", których zadaniem jest
dostarczenie pojedynczych funkcjonalności np. budowania konkretnego
formularza. Kolega z zespołu korzysta raczej z metod prywatnych. Oba
podejścia tak samo dobre. Każdy ma swoje.

To są takie smaczki, które powodują, że jak czytasz kod to wiesz kto w
nim grzebał.

Tak swoją drogą to w tym przypadku można jeszcze połasić się na użycie
scalowych case classes.

Pozdrawiam
Bartek "Koziołek" Kuczyński
http://koziolekweb.pl
Lepiej pomyśleć dwa razy i zacząć programować
niż dwa razy programować i potem zacząć myśleć
 \     /
 ~00~
  \_/
   |||

Marcin Zajączkowski

unread,
Jul 8, 2011, 2:50:56 PM7/8/11
to warsza...@googlegroups.com
On 2011-07-08 20:34, Bartek Kuczy�ski wrote:
> @Marcin, tu chodzi raczej o pewne rozwi�zania na poziomie
> wykorzystania kodu. Ja pisz� z wykorzystaniem klas wewn�trznych oraz
> du�ej ilo�ci takich r�nych "mikrotyp�w", kt�rych zadaniem jest
> dostarczenie pojedynczych funkcjonalno�ci np. budowania konkretnego
> formularza. Kolega z zespo�u korzysta raczej z metod prywatnych. Oba
> podej�cia tak samo dobre. Ka�dy ma swoje.
>
> To s� takie smaczki, kt�re powoduj�, �e jak czytasz kod to wiesz kto w
> nim grzebaďż˝.

Jasne, swojego czasu robi�em regularne przegl�du kodu wielu os�b i
niekt�re konstrukcj�/podej�cia by�y naprawd� charakterystyczne (no mo�e
akurat podej�cia z "mikrotypami" nie spotka�em). Niemniej i tak og�lne
mo�liwo�ci w Javie, aby by� oryginalnym s� du�o mniejsze (chocia�
wspomniana tu Scala, czy Groovy znowu idďż˝ w tďż˝ stronďż˝ :) ).


Pozdrawiam
Marcin


>
> Tak swoj� drog� to w tym przypadku mo�na jeszcze po�asi� si� na u�ycie
> scalowych case classes.
>
> Pozdrawiam
> Bartek "Kozio�ek" Kuczy�ski
> http://koziolekweb.pl
> Lepiej pomy�le� dwa razy i zacz�� programowa�
> ni� dwa razy programowa� i potem zacz�� my�le�
> \ /
> ~00~
> \_/
> |||
>
>
>
> W dniu 8 lipca 2011 20:28 u�ytkownik Marcin Zaj�czkowski <msz...@wp.pl> napisa�:


>> On 2011-07-08 09:07, iirekm wrote:

>>> Ehh, ilu developer�w tyle podej�� do programowania. Jak z kim� pracujesz
>>> przez jaki� czas, to nawet bez zagl�dania do historii SVN-a z du�ym
>>> prawdopodobie�stwem mo�na powiedzie� kto to napisa�. :-)


>> Tak, ale teraz jest to trudniejsze. W czasach C (albo lepiej Assemblera)

>> �atwiej by�o wypracowa� sw�j styl "optymalizacji" :).


>>
>>
>> Pozdrawiam
>> Marcin
>>
>> --
>> http://solidsoft.wordpress.com/ - Working code is not enough
>>
>> --

>> Otrzymujesz t� wiadomo��, poniewa� subskrybujesz grup� dyskusyjn� Google o nazwie "Warszawa Java User Group (Warszawa JUG)".
>>
>> Aby zamieszcza� posty w tej grupie, wy�lij e-mail na adres warsza...@googlegroups.com.
>> Aby anulowa� subskrypcj� tej grupy, wy�lij e-mail na adres warszawa-jug...@googlegroups.com.
>> Aby uzyska� wi�cej informacji, odwied� t� grup� pod adresem http://groups.google.com/group/warszawa-jug?hl=pl.

Reply all
Reply to author
Forward
0 new messages