@RefreshScope 似乎忽略了 Mockito 的嘲笑

Posted

技术标签:

【中文标题】@RefreshScope 似乎忽略了 Mockito 的嘲笑【英文标题】:@RefreshScope seems to ignore Mockito's mocks 【发布时间】:2016-06-29 07:20:22 【问题描述】:

我正在使用 Spring Boot 和 Spring Cloud Config 服务来实现一个服务来提供配置值。在我的服务中,我有几个配置值需要在远程 Git 存储库中的值更改时刷新,我使用 @RefreshScope 来启用该功能。

当我尝试在该服务中为RestTemplate 注入模拟时,问题出现了,它似乎忽略了它并改用自动装配的实例。如果我注释掉注释,它似乎工作正常。

这是服务的代码:

@Service
@RefreshScope
public class MyServiceImpl implements MyService 

    private static final Logger LOG = Logger.getLogger(MyServiceImpl.class);

    @Autowired
    public RestTemplate restTemplate;

    @Value("$opts.default")
    private String default;

    @Value("$opts.address")
    private String address;

    @Value("$opts.separator")
    private String separator;

    ...


  

测试源码:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class ServiceTest 

    @Mock
    private RestTemplate restTemplate;

    @Autowired
    @InjectMocks
    private MyServiceImpl service;

    @Before
    public void setUp() 
        MockitoAnnotations.initMocks(this);
    

    public void testMethod() throws Exception 
        when(restTemplate.postForObject(anyString(), any(), eq(ServiceResponse.class), anyMap())).thenReturn(getSuccessfulResponse());

        ServiceResponse response = service.doYourStuff();

        Assert.assertNotNull(response);
        Assert.assertTrue(response.isSuccessful());
    

    ...
  

【问题讨论】:

【参考方案1】:

当添加@RefreshScope 时,bean 成为代理而不是实际的原始实现。目前RestTemplate 设置在代理而不是基础实例上。 (如果您进行调试,您会发现您的MyServiceImpl 实际上更像是MyServiceImpl$SpringCgLib#353234 的一个实例。

要修复,您需要使用 ReflectionTestUtilsAopTestUtils 手动设置依赖项。后者是获取实际代理。

删除@InjectMocks注解并在初始化模拟后将以下内容添加到您的setup方法中:

Object actualTarget = AopTestUtils.getUltimateTargetObject(service);
ReflectionTestUtils.setfield(actualTarget, "restTemplate", restTemplate);

对于 4.2 之前的版本,以下可能会解决问题

Object actualTarget = (service instanceof Advised) ? ((Advised) service).getTargetSource().getTarget() : service;

问题是 Mockito 没有检测到代理,只是设置了字段。 ReflectionTestUtils 也没有检测到代理,因此需要手动展开。实际上,我之前曾多次踏入这个陷阱,这导致我今天早上创建了SPR-14050,并将其嵌入ReflectionTestUtils 以减轻痛苦。

【讨论】:

谢谢!我将自己添加为该问题的观察者 顺便说一句,AopTestUtils 是您使用的类而不是 AopUtils 吗? Spring-cloud Angel.SR6 使用不包含该类的 Spring 4.1.9。 AopTestUtils 是在 Spring 4.2.0 中引入的,之前的版本有替代方案吗? 复制我猜的代码...问题是你需要解包的实例,AopUtilsAopProxyUtils 只检测类型但是在这里没有帮助,因为你不仅需要对象方式。我添加了另一个可能有帮助的代码 sn-p... 抱歉:在目标 [class service.impl.MyServiceImpl] 上找不到类型为 [null] 的字段 [restTemplate]

以上是关于@RefreshScope 似乎忽略了 Mockito 的嘲笑的主要内容,如果未能解决你的问题,请参考以下文章

@RefreshScope 和 /refresh 不起作用

Spring Cloud @RefreshScope 原理分析:扫描 Bean 定义

Spring Cloud @RefreshScope 原理分析:代理类调用流程

@RefreshScope 加在 Quartz 触发器类导致异常问题分析

解决 @RefreshScope 导致定时任务注解 @Scheduled 失效

解决 @RefreshScope 导致定时任务注解 @Scheduled 失效