Pregunta

¿Existe un método limpio de burlarse de una clase con parámetros genéricos? Digamos que tengo que burlarme de una clase Foo<T> que necesito pasar a un método que espera un Foo<Bar>. Puedo hacer lo siguiente con bastante facilidad:

Foo mockFoo = mock(Foo.class);
when(mockFoo.getValue).thenReturn(new Bar());

Suponiendo que getValue() devuelve el tipo genérico T. Pero eso tendrá gatitos cuando más tarde lo pase a un método esperando <=>. ¿Es el casting el único medio para hacer esto?

¿Fue útil?

Solución

Creo que necesitas lanzarlo, pero no debería ser tan malo:

Foo<Bar> mockFoo = (Foo<Bar>) mock(Foo.class);
when(mockFoo.getValue).thenReturn(new Bar());

Otros consejos

Otra forma de evitar esto es usar la anotación @Mock en su lugar. No funciona en todos los casos, pero se ve mucho más sexy :)

Aquí hay un ejemplo:

@RunWith(MockitoJUnitRunner.class)
public class FooTests {

    @Mock
    public Foo<Bar> fooMock;

    @Test
    public void testFoo() {
        when(fooMock.getValue()).thenReturn(new Bar());
    }
}

El MockitoJUnitRunner inicializa los campos anotados con <=> .

Siempre puede crear una clase / interfaz intermedia que satisfaga el tipo genérico que desea especificar. Por ejemplo, si Foo fuera una interfaz, podría crear la siguiente interfaz en su clase de prueba.

private interface FooBar extends Foo<Bar>
{
}

En situaciones donde Foo es una clase no final , puede extender la clase con el siguiente código y hacer lo mismo:

public class FooBar extends Foo<Bar>
{
}

Entonces podría consumir cualquiera de los ejemplos anteriores con el siguiente código:

Foo<Bar> mockFoo = mock(FooBar.class);
when(mockFoo.getValue()).thenReturn(new Bar());

Cree un método de utilidad de prueba . Especialmente útil si lo necesita más de una vez.

@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);
}

Aquí hay un caso interesante: el método recibe una colección genérica y devuelve una colección genérica del mismo tipo base. Por ejemplo:

Collection<? extends Assertion> map(Collection<? extends Assertion> assertions);

Este método se puede burlar con la combinación de Mockito anyCollectionOf matcher y la respuesta.

when(mockedObject.map(anyCollectionOf(Assertion.class))).thenAnswer(
     new Answer<Collection<Assertion>>() {
         @Override
         public Collection<Assertion> answer(InvocationOnMock invocation) throws Throwable {
             return new ArrayList<Assertion>();
         }
     });

Estoy de acuerdo en que no se deben suprimir las advertencias en clases o métodos, ya que se podrían pasar por alto otras advertencias suprimidas accidentalmente. Pero en mi humilde opinión, es absolutamente razonable suprimir una advertencia que afecta solo a una sola línea de código.

@SuppressWarnings("unchecked")
Foo<Bar> mockFoo = mock(Foo.class);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top