Utilizzo di Mockito per deridere classi con parametri generici
Domanda
Esiste un metodo pulito per deridere una classe con parametri generici? Supponiamo di dover deridere una classe Foo<T>
che devo passare a un metodo che prevede un Foo<Bar>
. Posso fare quanto segue abbastanza facilmente:
Foo mockFoo = mock(Foo.class);
when(mockFoo.getValue).thenReturn(new Bar());
Supponendo che getValue()
restituisca il tipo generico T
. Ma questo avrà gattini quando in seguito lo passerò a un metodo in attesa di <=>. Il casting è l'unico mezzo per farlo?
Soluzione
Penso che tu debba lanciarlo, ma non dovrebbe essere così male:
Foo<Bar> mockFoo = (Foo<Bar>) mock(Foo.class);
when(mockFoo.getValue).thenReturn(new Bar());
Altri suggerimenti
Un altro modo per aggirare questo è usare invece @Mock
annotazione.
Non funziona in tutti i casi, ma sembra molto più sexy :)
Ecco un esempio:
@RunWith(MockitoJUnitRunner.class)
public class FooTests {
@Mock
public Foo<Bar> fooMock;
@Test
public void testFoo() {
when(fooMock.getValue()).thenReturn(new Bar());
}
}
Il MockitoJUnitRunner
inizializza i campi annotati con <=> .
Puoi sempre creare una classe / interfaccia intermedia in grado di soddisfare il tipo generico che desideri specificare. Ad esempio, se Foo fosse un'interfaccia, potresti creare la seguente interfaccia nella tua classe di test.
private interface FooBar extends Foo<Bar>
{
}
In situazioni in cui Foo è una classe non finale , puoi semplicemente estendere la classe con il seguente codice e fare la stessa cosa:
public class FooBar extends Foo<Bar>
{
}
Quindi puoi utilizzare uno degli esempi sopra con il seguente codice:
Foo<Bar> mockFoo = mock(FooBar.class);
when(mockFoo.getValue()).thenReturn(new Bar());
Crea un metodo dell'utilità di test . Utile specialmente se ne hai bisogno per più di una volta.
@Test
public void testMyTest() {
// ...
Foo<Bar> mockFooBar = mockFoo();
when(mockFooBar.getValue).thenReturn(new Bar());
Foo<Baz> mockFooBaz = mockFoo();
when(mockFooBaz.getValue).thenReturn(new Baz());
Foo<Qux> mockFooQux = mockFoo();
when(mockFooQux.getValue).thenReturn(new Qux());
// ...
}
@SuppressWarnings("unchecked") // still needed :( but just once :)
private <T> Foo<T> mockFoo() {
return mock(Foo.class);
}
Ecco un caso interessante: il metodo riceve una raccolta generica e restituisce una raccolta generica dello stesso tipo di base. Ad esempio:
Collection<? extends Assertion> map(Collection<? extends Assertion> assertions);
Questo metodo può essere deriso con la combinazione di Mockito anyCollectionOf matcher e la risposta.
when(mockedObject.map(anyCollectionOf(Assertion.class))).thenAnswer(
new Answer<Collection<Assertion>>() {
@Override
public Collection<Assertion> answer(InvocationOnMock invocation) throws Throwable {
return new ArrayList<Assertion>();
}
});
Concordo sul fatto che non si dovrebbero sopprimere gli avvisi in classi o metodi in quanto si potrebbero trascurare gli altri avvisi soppressi accidentalmente. Ma IMHO è assolutamente ragionevole sopprimere un avviso che riguarda solo una singola riga di codice.
@SuppressWarnings("unchecked")
Foo<Bar> mockFoo = mock(Foo.class);