2013-07-28 12 views
6

Mam twardy czas trudny do realizacji testów jednostkowych na moich zajęciach fasoli JSF podporowych ... Na przykład niektóre ze sposobów wykorzystania parametrów sesji lub żądania, uzyskany przy użyciu tego rodzaju kodu:Jak przetestować metody komponentu bean JSF, które używają parametrów sesji?

FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("paramKey");.

Moje pytanie brzmi: jak mogę przetestować metodę, która pobiera wartości z sesji lub żądania?

+0

Jakiego szkieletu używasz do testowania fasoli zarządzanej przez JSF? –

+1

Próbuję uniknąć konieczności testowania na zarządzanym kontenerze (na przykład przy użyciu Arquilliana). Moim celem jest wyśmiewanie wszystkich wywołań metod do wstrzykniętych zasobów, ponieważ zajmuję się [EasyGloss] (https://java.net/projects/easygloss). Jeśli masz lepszą strategię, daj mi znać :-) –

Odpowiedz

8

Co zwykle robię, to unikać wywoływania metod statycznych w ziarnach Chcę przetestować. Oznacza to, że Twój aktualny kod ma być refaktoryzowany:

FacesContext.getCurrentInstance().getExternalContext() 
    .getSessionMap().get("paramKey"); 

Czy są sposoby na przetestowanie ich za pomocą wywołań metod statycznych? Prawdopodobnie tak, ale oni doprowadzili mnie do wielu kłopotów bardziej niż pomocy. Więc na koniec pozbyłem się ich i zmieniłem swój projekt. Po prostu niech zrobi to druga fasola (o której będziesz się później pozorować). W twoim przypadku, stworzyć @SessionScoped fasoli, który zarządza tę funkcjonalność:

@ManagedBean 
@SessionScoped 
public class SessionBean{ 

    public Object getSessionParam(String paramKey){ 
     FacesContext.getCurrentInstance().getExternalContext() 
      .getSessionMap().get(paramKey); 
    } 

} 

i wstrzyknąć że ziarna z każdego ziarna, który potrzebuje go (ja zazwyczaj rozciągają się moim zdaniem/request fasolę z abstrakcyjnego fasoli, która ma go, więc don „t muszą wdrożyć go w każdym pojedynczym fasoli):

@ManagedBean 
@RequestScoped 
public class RequestBean{ 

    @ManagedProperty(value="#{sessionBean}") 
    private SessionBean sessionBean; 

    public void accessSessionParam(){ 
     sessionBean.getSessionParam("name"); 
    } 

} 

ten sposób można łatwo uzyskać dostęp do metody statyczne, za pośrednictwem pomocniczego SessionBean. Następnie, jak go przetestować? Wystarczy utworzyć makiety z nim (przy użyciu Mockito, na przykład):

public class Test{ 

    public void test1(){ 
     SessionBean sb = Mockito.mock(SessionBean.class); 
     //Mock your 'getSessionParam' method 
     ValueBean vb = new ValueBean(); 
     Mockito.when(sb.getSessionParam(Mockito.anyString()).thenReturn(vb); 
     //Create your bean to test and set your mock to it 
     RequestBean rb = new RequestBean(); 
     rb.setSessionBean(sb); 
     //here you can test your RequestBean assuming 
     //sessionBean.getSessionParam() 
     //will return vb for every single call 
    } 

} 
+0

Przyjemne podejście. Tylko jedna obserwacja: metoda 'getSessionParam' nie musi być w ManagedBean, może być w POJO, prawda? Ponieważ nie używa żadnych zasobów specyficznych dla fasoli ... –

+0

Zaletą fasoli zarządzanej przez JSF jest to, że struktury tworzą je raz dla podanego zakresu. Oznacza to, że jeśli ustawisz zakres sesji, zostanie utworzony tylko jeden raz na sesję użytkownika i automatycznie wstrzyknięty. Możesz utworzyć zwykły komponent i ręcznie go tworzyć za każdym razem, gdy chcesz go użyć, ale oznacza to marnowanie większych zasobów.I, oczywiście, będzie działać tylko wtedy, gdy masz zasięg JSF. –

+0

Należy również pamiętać, że używasz Dependency Injection, pozwalając ramce ustawić swój komponent. Pamiętaj, że [DI ułatwia koncepcję testowania] (http://stackoverflow.com/a/130862/1199132). –

6

Jest possible to mock FacesContext ale jest to mniej niż idealne. Mockito przykład:

import javax.faces.context.FacesContext; 
import org.mockito.Mockito; 
import org.mockito.invocation.InvocationOnMock; 
import org.mockito.stubbing.Answer; 

public abstract class ContextMocker extends FacesContext { 
    private ContextMocker() {} 

    private static final Release RELEASE = new Release(); 

    private static class Release implements Answer<Void> { 
    @Override 
    public Void answer(InvocationOnMock invocation) throws Throwable { 
     setCurrentInstance(null); 
     return null; 
    } 
    } 

    public static FacesContext mockFacesContext() { 
    FacesContext context = Mockito.mock(FacesContext.class); 
    setCurrentInstance(context); 
    Mockito.doAnswer(RELEASE) 
     .when(context) 
     .release(); 
    return context; 
    } 
} 

Jeśli platforma wspiera go, wolą CDI do JSF udało fasoli. CDI ma sprawdzanie zależności statycznych i wstrzykuje proxy, aby zapobiec wyciekowi zakresu. CDI nie obsługuje wszystkich funkcji JSF, ale w razie potrzeby jest względnie łatwe do connect JSF managed beans to CDI.

Fasolki zarządzane przez JSF ograniczają zasięg typów iniekcyjnych, ale nawet może to prowadzić do przecieków. Na przykład zmienna #{sessionScope} może zostać wstrzyknięta do komponentu bean sesji, mimo że obiekt należy do zakresu o wymaganym zakresie: ExternalContext. Możliwe jest przezwyciężenie tego przez writing your own JSF bean proxies.

Uwaga: większość z nich została napisana z myślą o Java EE 6; rzeczy mogły się poprawić dzięki Java EE 7.

+0

Dzięki za odpowiedź! Czy możesz podać przykład użycia tego wyśmianego FaceContext w teście? –

+1

@FelipeReis postępuj zgodnie z pierwszym linkiem – McDowell

+0

oops, przepraszam McDowell! Dzięki jeszcze raz! –

Powiązane problemy