Spring 模拟CGLIB代理服务的属性不工作
在Junit测试中尝试模拟服务的属性时,我遇到了一个问题:Spring 模拟CGLIB代理服务的属性不工作,spring,mocking,cglib,proxies,Spring,Mocking,Cglib,Proxies,在Junit测试中尝试模拟服务的属性时,我遇到了一个问题: @ContextConfiguration("classpath:application-config.xml") @RunWith(SpringJUnit4ClassRunner.class) public class FooServiceTests { @Autowired private FooServiceImpl fooService; @Test public void testFoo()
@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,我就不知道如何使它工作。任何帮助都将不胜感激
提前问候和感谢。简短回答
必须在目标对象上创建并设置字段:
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;
}
…长的
这个问题相当复杂,但可以解决。正如您所猜测的,这是使用CGLIB代理的副作用。原则上,Spring创建了FooServiceImpl
的一个子类,名为类似于FooServiceImpl$enhancerbyglib
。此子类包含对原始FooServiceImpl
的引用以及。。。所有字段FooServiceImpl
都有(这是可以理解的-这是一个子类)
因此实际上有两个变量:
FooServiceImpl$EnhancerByCGLIB.fooDao
和FooServiceImpl.fooDao
。您正在为前者分配模拟,但您的服务使用后者。。。不久前我就意识到了这个陷阱。@frandiaz83:很高兴我能帮上忙!考虑和/或投票正确的答案,指向未来读者正确的解决方案。当然。我已经接受了答案,但我不能投赞成票,因为我没有足够的声誉。。。再次感谢。unwrapFooService()
有一些问题:未解析的名称a
,如果条件不正确,则缺少返回。我冒昧地编辑了它,使它(为我)编译并工作。另外,+1再也不需要使用Spring 4.2自己编写unwrapFooService
。退房