fra*_*ayz 17 spring mocking cglib proxies
尝试在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);
}
}
Run Code Online (Sandbox Code Playgroud)
嘲弄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";
}
}
Run Code Online (Sandbox Code Playgroud)
正如我们所看到的,实际服务意味着返回"foo",但是测试会模仿dao,因此服务返回"var".我知道这是一个与CGLIB代理相关的东西,但我无法弄清楚如何在不使用fooDao属性的setter的情况下使其工作.任何帮助,将不胜感激.
提前问候并表示感谢.
Tom*_*icz 40
您必须打开代理并在目标对象上设置字段:
ReflectionTestUtils.setField(unwrapFooService(), "fooDao", mockFooDao);
Run Code Online (Sandbox Code Playgroud)
在unwrapFooService()
可被定义为如下:
private FooServiceImpl unwrapFooService() {
if(AopUtils.isAopProxy(fooService) && fooService instanceof Advised) {
Object target = ((Advised) fooService).getTargetSource().getTarget();
return (FooServiceImpl)target;
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
问题非常复杂,但可以解决.正如您所猜测的那样,这是使用CGLIB代理的副作用.原则上,Spring创建一个FooServiceImpl
类似于你的命名的子类FooServiceImpl$EnhancerByCGLIB
.这个子类包含对原始的引用FooServiceImpl
以及...所有字段的引用FooServiceImpl
(这是可以理解的 - 这是一个子类).
所以实际上有两个变量:FooServiceImpl$EnhancerByCGLIB.fooDao
和FooServiceImpl.fooDao
.你正在为前者分配一个模拟但你的服务使用后者......我前段时间写过这个陷阱.
归档时间: |
|
查看次数: |
3871 次 |
最近记录: |