2012-12-06 29 views
8

Używam GWTP, dodając warstwę kontraktu, aby streścić wiedzę między prezenterem a Viewem, i jestem całkiem zadowolony z wyniku z GWTP. Testuję moich prezenterów z Mockito.Testowanie prezentera GWTP z asynchronicznymi wywołaniami

Ale z czasem okazało się, że trudno jest utrzymać czystego prezentera z jego testami. Jest kilka rzeczy, które poprawiłem, ale wciąż nie byłem zadowolony.

Uważam, że sedno sprawy jest następujące: Moi prezenterzy często wymagają wywołania asynchronicznego lub generalnie wywołują metodę obiektów z wywołaniem zwrotnym, aby kontynuować przepływ mojego prezentera (zazwyczaj są zagnieżdżani).

Na przykład:

this.populationManager.populate(new PopulationCallback() 
    { 
    public void onPopulate() 
    { 
     doSomeStufWithTheView(populationManager.get()); 
    } 
    }); 

W moich testach, skończyło się zweryfikować ludności() wezwanie wyśmiewali obiektu PopulationManager. Następnie, aby utworzyć kolejny test w metodzie doSomeStufWithTheView().

Szybko jednak odkryłem, że był to zły projekt: każda zmiana lub refaktoryzacja zakończyła się zepsuł wiele moich testów i zmusiła mnie do stworzenia od początku innych, mimo że funkcjonalność prezentera się nie zmieniła! Plus Nie testowałem, czy wywołanie zwrotne było faktycznie tym, czego chciałem.

Więc starałem się używać Mockito metody doAnswer aby nie złamać moje prezentera przepływ badań:

doAnswer(new Answer(){ 
    public Object answer(InvocationOnMock invocation) throws Throwable 
    { 
     Object[] args = invocation.getArguments(); 
     ((PopulationCallback)args[0]).onPopulate(); 
     return null; 
    } 
}).when(this.populationManager).populate(any(PopulationCallback.class)); 

ja uwzględnione kod, aby była ona mniej gadatliwy (i wewnętrznie mniej zależne do pozycji Arg):

doAnswer(new PopulationCallbackAnswer()) 
    .when(this.populationManager).populate(any(PopulationCallback.class)); 

Więc gdy drwi z populationManager, mogę jeszcze przetestować przepływ mojego prezentera, w zasadzie tak:

@Test 
public void testSomeStuffAppends() 
{ 
    // Given 
    doAnswer(new PopulationCallbackAnswer()) 
    .when(this.populationManager).populate(any(PopulationCallback.class)); 

    // When 
    this.myPresenter.onReset(); 

    // Then 
    verify(populationManager).populate(any(PopulationCallback.class)); // That was before 
    verify(this.myView).displaySomething(); // Now I can do that. 
} 

Zastanawiam się, czy jest to dobre wykorzystanie metody doAnswer, czy też jest to zapach kodu i można użyć lepszego projektu?

Zwykle moi prezenterzy zwykle używają innych obiektów (takich jak wzór Mediatora) i wchodzą w interakcję z widokiem. Mam jakiegoś prezentera z kilkoma setkami (~ 400) linii kodu.

Ponownie, czy jest to dowód złego projektu, czy też jest to normalne, że prezenter jest gadatliwy (ponieważ używa innych obiektów)?

Czy ktoś słyszał o jakimś projekcie, który używa GWTP i testuje swojego podawcy w czysty sposób?

Mam nadzieję, że wyjaśniłem w sposób kompleksowy.

Z góry dziękuję.

PS: Jestem całkiem nowy w Stack Overflow, a ponadto brakuje mojego angielskiego, jeśli moje pytanie wymaga czegoś do poprawienia, proszę powiedz mi.

Odpowiedz

1

Można użyć ArgumentCaptor: Sprawdź ten blog post przed więcej szczegółów.

+0

to jest po prostu idealne !!! +1 – EMM

0

Jeśli dobrze rozumiem, pytasz o projekt/architekturę.

To nie powinno być traktowane jako odpowiedź, to tylko moje przemyślenia.

Jeśli Śledzę Kod:

public void loadEmoticonPacks() { 
    executor.execute(new Runnable() { 
     public void run() { 
      pack = loadFromServer(); 
      savePackForUsageAfter(); 
     } 
    }); 
} 

ja zwykle nie licz na egzekutora i po prostu sprawdzić, czy konkretne metody pracy przy załadunku i zapisywania. Tak więc executor jest tylko narzędziem, które zapobiega długotrwałym operacjom w wątku UI.

Jeśli mam coś takiego:

accountManager.setListener(this); 
.... 
public void onAccountEvent(AccountEvent event) { 
.... 
} 

będę sprawdź najpierw, że zapisy na wydarzenia (i niektóre wypisany na zniszczenie), a także chciałbym sprawdzić, że onAccountEvent nie oczekuje scenariuszy.

UPD1. Prawdopodobnie w przykładzie 1 lepiej byłoby wydobyć metodę loadFromServerAndSave i sprawdzić, czy nie jest ona wykonywana w wątku UI, a także sprawdzić, czy robi wszystko zgodnie z oczekiwaniami.

UPD2. Lepiej używać frameworków takich jak Guava Bus do przetwarzania zdarzeń.

0

Używamy tego wzoru doAnswer w naszych testach prezenterów i zwykle działa dobrze. Jedno zastrzeżenie: Jeśli przetestujesz to w ten sposób, skutecznie usuniesz asynchroniczny charakter połączenia, to znaczy, że wywołanie zwrotne jest wykonywane natychmiast po zainicjowaniu połączenia z serwerem.

Może to prowadzić do nieodkrytych warunków wyścigu. Aby to sprawdzić, można wykonać dwuetapowy proces: podczas wywoływania serwera metoda odpowiedzi zapisuje tylko wywołanie zwrotne. Następnie, gdy jest to właściwe w teście, wywołujesz odpowiedź przypominającą flush() lub Success() (proponuję utworzyć klasę użyteczności dla tego, która może być ponownie użyta w innych okolicznościach), abyś mógł kontrolować, kiedy wywołanie zwrotne dla wyniku jest naprawdę wywoływane.

Powiązane problemy