taglibs tag form spring mocking cglib proxies

form - taglib spring jsp



Simular una propiedad de un servicio de proxy CGLIB no funciona (1)

Tengo un problema al intentar simular una propiedad de un servicio desde una prueba de Junit:

@ContextConfiguration("classpath:application-config.xml") @RunWith(SpringJUnit4ClassRunner.class) public class FooServiceTests { @Autowired private FooServiceImpl fooService; @Test public void testFoo() { String str = fooService.foo(); assertEquals("Var", str); } @Before public void mockFooDao() throws Exception { FooDao mockFooDao = Mockito.mock(FooDao.class); Mockito.when(mockFooDao.foo()).thenReturn("Var"); ReflectionTestUtils.setField(fooService, "fooDao", mockFooDao); } }

La burla de fooDao no tiene ningún efecto ya que el resultado no es el esperado. Aquí está el código tanto del servicio como del dao:

@Service("fooService") public class FooServiceImpl implements FooService { @Autowired protected FooDao fooDao; @Override public String foo() { return fooDao.foo(); } } @Repository public class FooDaoImpl implements FooDao { @Override public String foo() { return "foo"; } }

Como podemos ver, el servicio real está destinado a devolver "foo", pero la prueba se burla del dao, por lo que el servicio devuelve "var". Sé que es una cosa relacionada con el proxy CGLIB, pero no puedo averiguar cómo hacer que funcione sin usar un setter para la propiedad fooDao. Cualquier ayuda sería apreciada.

Saludos y gracias de antemano.


Respuesta corta

Debe desenvolver el proxy y establecer el campo en el objeto de destino:

ReflectionTestUtils.setField(unwrapFooService(), "fooDao", mockFooDao);

El unwrapFooService() se puede definir de la siguiente manera:

private FooServiceImpl unwrapFooService() { if(AopUtils.isAopProxy(fooService) && fooService instanceof Advised) { Object target = ((Advised) fooService).getTargetSource().getTarget(); return (FooServiceImpl)target; } return null; }

...largo

El problema es bastante complejo, pero solucionable. Como ha adivinado, este es un efecto secundario de los proxies CGLIB que se están utilizando. En principio, Spring crea una subclase de su FooServiceImpl llamada similar a FooServiceImpl$EnhancerByCGLIB . Esta subclase contiene una referencia al FooServiceImpl original y también a ... todos los campos que tiene FooServiceImpl (lo cual es comprensible, esta es una subclase).

Entonces, en realidad hay dos variables: FooServiceImpl$EnhancerByCGLIB.fooDao y FooServiceImpl.fooDao . Está asignando un simulacro al primero, pero su servicio usa el segundo ... Hace poco wrote sobre estos escollos.