一尘不染

@RefreshScope似乎忽略了Mockito的模拟

spring-boot

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

    ...
  }

阅读 309

收藏
2020-05-30

共1个答案

一尘不染

在添加@RefreshScopebean时,它将成为代理而不是实际的原始实现。当前在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到其中可以减轻一些痛苦。

2020-05-30