模拟CGLIB代理服务的属性不起作用
尝试从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);
}
}
模拟fooDao无效,因为结果不是预期的。这是服务和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";
}
}
如我们所见,实际的服务旨在返回“ foo”,但是测试模拟了dao,因此服务返回了“ var”。我知道这是与CGLIB代理相关的事情,但是我不知道如何在不对fooDao属性使用setter的情况下使其工作。任何帮助,将不胜感激。
谨在此致谢。
回答:
Short answer
你必须解开代理并在目标对象上设置字段:
ReflectionTestUtils.setField(unwrapFooService(), "fooDao", mockFooDao);
在unwrapFooService()可被定义为如下:
private FooServiceImpl unwrapFooService() { if(AopUtils.isAopProxy(fooService) && fooService instanceof Advised) {
Object target = ((Advised) fooService).getTargetSource().getTarget();
return (FooServiceImpl)target;
}
return null;
}
…long one
这个问题很复杂,但是可以解决。你已经猜到这是使用CGLIB代理的副作用。原则上,Spring创建你的FooServiceImpl
名为的子类,类似于FooServiceImpl$EnhancerByCGLIB
。该子类包含对原始以及所有字段的引用(这是可以理解的-这是一个子类)。FooServiceImplFooServiceImpl
因此实际上有两个变量:FooServiceImpl$EnhancerByCGLIB.fooDao
和FooServiceImpl.fooDao
。你分配一个模拟前者,但你的服务使用后者。我写了前段时间关于这个陷阱。
以上是 模拟CGLIB代理服务的属性不起作用 的全部内容, 来源链接: utcz.com/qa/404862.html