@RefreshScope似乎忽略了莫基托的嘲笑



我正在使用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());
    }
    ...
  }

添加@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中以减轻疼痛。

相关内容

  • 没有找到相关文章

最新更新