Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cassandra/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring 模拟CGLIB代理服务的属性不工作_Spring_Mocking_Cglib_Proxies - Fatal编程技术网

Spring 模拟CGLIB代理服务的属性不工作

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()

在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,我就不知道如何使它工作。任何帮助都将不胜感激

提前问候和感谢。

简短回答 必须在目标对象上创建并设置字段:

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
。退房