模拟CGLIB代理服务的属性不起作用

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.fooDaoFooServiceImpl.fooDao.你正在为前者分配一个模拟但你的服务使用后者......我前段时间写过这个陷阱.

  • 使用Spring 4.2不再需要自己编写`unwrapFooService`.查看http://stackoverflow.com/a/30461953/2504224 (4认同)