模拟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.fooDaoFooServiceImpl.fooDao。你分配一个模拟前者,但你的服务使用后者。我写了前段时间关于这个陷阱。

以上是 模拟CGLIB代理服务的属性不起作用 的全部内容, 来源链接: utcz.com/qa/404862.html

回到顶部