我正在使用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
)。
要解决此问题,您需要使用ReflectionTestUtils
和手动设置依赖项AopTestUtils
。后者是获取实际的代理。
初始化模拟后,删除@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
到其中可以减轻一些痛苦。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句