2012-04-25 15 views
10

Metoda chcę testu pętli for z logiki dla każdego elementu w BLIST:Mockito ClassCastException

class A { 
    void someMethod(){ 

     for(B b: bList){ 
      //some logic for b 
     } 
    } 
} 

uzyskać wyjątek podczas wykonywania następujący test:

@RunWith(MockitoJUnitRunner.class) 
class ATest { 

    @Mock 
    private B b; 

    @Mock 
    private Map<Int, List<B>> bMap; 

    @Mock(answer = Answers.RETURNS_DEEP_STUBS) 
    private List<B> bList; 

    @Spy 
    @InjectMocks 
    private C c; 
    .... 

    @Test 
    public void test(){ 

     //this line executes fine 
     when(bList.size()).thenReturn(1); 

     //strangely this works fine 
     when(bMap.get(any())).thenReturn(bList); 

     //ClassCastException 
     when(bList.get(0)).thenReturn(b); // or when(bList.get(anyInt())).thenReturn(b); 

     c.methodIWantToTest(); 
    } 
} 

Wyjątek otrzymuję jest:

java.lang.ClassCastException: 
org.mockito.internal.creation.jmock.ClassImposterizer$ClassWithSuperclassToWorkAroundCglibBug$$EnhancerByMockitoWithCGLIB$$ cannot be cast to xyz.B

Czy ktoś napotkał to wcześniej i wymyślił obejście tego problemu?

Szukałem rozwiązania i nie natknąłem się kilka linków: http://code.google.com/p/mockito/issues/detail?id=251 i http://code.google.com/p/mockito/issues/detail?id=107

+0

To może być istniejący problem jak wskazano w linkach. –

+2

Naprawdę próbujesz kpić z listy i mapy lub czy to tylko ilustruje problem? Dlaczego po prostu nie użyjesz implementacji ArrayList i HashMap i nie wstrzykniesz? – jhericks

+0

@jhericks Tak, masz rację, powinienem przełączyć się na użycie implementacji ArrayList i HashMap. Dzięki –

Odpowiedz

18

Jak this link you posted wskazuje, masz napotkał błąd z Answers.RETURNS_DEEP_STUBS.

Nie widzę żadnego powodu, aby faktycznie użyć RETURNS_DEEP_STUBS w przykładowym kodzie. Naprawdę powinieneś spróbować ocenić, czy potrzebujesz głębokich dystansów, ponieważ, jako Mockito docs say, "za każdym razem, gdy próbka wraca, udaje, że wróżka umiera." Jeśli możesz, po prostu to zrób i twój przykład zadziała. Jeśli jednak nalegasz na używanie głębokich kodów pośredniczących, możesz zhakować ten błąd, przesyłając wartość zwracaną z wywołania metody na Object. Na przykład, zastąp linię w kodzie:

when((Object)bList.get(0)).thenReturn(b); 

Wszystko to, co się mówi, ja osobiście zgadzam się z @jhericks. Najlepszym rozwiązaniem jest prawdopodobnie użycie rzeczywistego ArrayList, który zawiera Twoją próbę, a nie kpiny z List. Jedynym problemem jest wstrzyknięcie twojej listy, więc musisz użyć @Spy. Na przykład:

@RunWith(MockitoJUnitRunner.class) 
class ATest{ 
    private B b = mock(B.class); 
    @Spy 
    private List<B> bList = new ArrayList<B>() {{ add(b); }}; 

    @InjectMocks 
    private C c = new C(); 

    @Test 
    public void test(){ 
    c.methodIWantToTest(); 
    // verify results 
    } 
} 
+0

Próbowałem zarówno alternatywy i oboje działają. Widzę przypadek opisany w dokumentach Mockito i powstrzymam się od używania mocków do zwracania mocków. Dzięki. –

1

Właściwie wyszukiwałbym problemów z klasą Classpath i relaoding. Na liście mailingowej mockito i trackerach problemów można zgłaszać niektóre zgłaszane problemy do niewłaściwej ścieżki klasy (zła wersja słoika itp.) I do przeładowywania klas (niektóre słoje zostały przeładowane, ale nie mockito, co doprowadziło do utworzenia instancji klasy z niewłaściwym programem ładującym klasy).

@Aces mógłbyś podać więcej szczegółów, jak wersja i nazwa narzędzia używasz (Maven, specyfikacje, murowany, Play Framework, JRebel może, etc ...)

+0

Wymieniłem makiety na implementacje ArrayList i HashMap, a także próbowałem hackować przez upcasting zgodnie z sugestią w odpowiedzi. Oba rozwiązania działały dobrze. Nie sądzę więc, aby w projekcie występowały problemy z klasą klasu. Udało mi się przeprowadzić egzaminy testowe z drwinami do tej pory. –

0

Niestety nie jest możliwe

przypadków: testy na API:

interface ConfigurationBuilder {...} 
configurationBuilder.newServerAction("s1").withName("111")....create(); 

Głównym powodem tego jest utrzymanie zgodności wykorzystania na czasie kompilacji. Ale Mockito nie może obsługiwać rodzajowych w łańcuchy z RETURNS_MOCKS i opcji RETURNS_DEEP_STUBS ze względu na rodzaj skasowaniu w Java:

Builder/*<ServerActionBuilder>-erasured generic*/ b = configurationBuilder.newServerAction("s1"); 
b.withName("111")...create(); 

Wynik w przykładzie powyżej powinna być ServerAction ale w Mockito to Przedmiot generowanej klasy.

zobaczyć Issue: Can not Return deep stubs from generic method that returns generic type #484

Powiązane problemy