在 Spring 的构建后阶段之前注入 mock
Posted
技术标签:
【中文标题】在 Spring 的构建后阶段之前注入 mock【英文标题】:Injecting mock before Spring's post-construct phase 【发布时间】:2019-03-24 10:58:23 【问题描述】:基本上,问题就在标题中。
我遇到了一个问题,在构建后阶段,我的 bean(即在现在正在经历构建后阶段的 bean 中自动装配)已经被模拟,但是 Mockito.when()
描述的所有行为都不起作用,所有调用返回null
。
在搜索时我找到了this 解决方案。
但是是否有可能在不使用任何 3rd 方库的情况下使其工作?
测试类:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ContextConfiguration(classes = TestApplicationConfiguration.class)
public class ServiceTest
@Autowired
@Qualifier("test")
private PCLPortType pclPortType;
@MockBean
private ClearingHelper сlearingHelper;
@MockBean
private OrganizationCacheRepository organizationCacheRepository;
@Before
public void setup() throws Exception
OperationResultWithOrganizationSystemIdMappingList res = new OperationResultWithOrganizationSystemIdMappingList();
when(clearingHelper.getOrgIdSystemIdMapping(any(Keycloak.class))).thenReturn(res);
@Test
public void test() throws Exception
pclPortType.call("123");
测试配置:
@TestConfiguration
public class TestApplicationConfiguration
@Bean(name = "test")
public PCLPortType pclPortTypeForTest() throws JAXBException
...
@Bean
public Keycloak keycloak()
return Mockito.mock(Keycloak.class);
我想获取模拟 bean 的组件:
@Component
public class OrganizationCacheJob
private static final Logger logger =
LogManager.getLogger(OrganizationCacheJob.class);
private final ObjectFactory<Keycloak> factory;
private final ClearingHelper clearingHelper;
private final OrganizationCacheRepository organizationCacheRepository;
@Autowired
public OrganizationCacheJob(ObjectFactory<Keycloak> factory,
ClearingHelper clearingHelper,
OrganizationCacheRepository organizationCacheRepository)
this.factory = factory;
this.clearingHelper = ClearingHelper;
this.organizationCacheRepository = organizationCacheRepository;
@PostConstruct
public void updateCacheRepository()
doUpdateCacheRepository();
@Scheduled(cron = "$organization.cache.schedule")
public void start()
logger.info("Starting update organization cache.");
doUpdateCacheRepository();
logger.info("Job finished.");
private void doUpdateCacheRepository()
try
Keycloak keycloak = factory.getObject();
OperationResultWithOrganizationSystemIdMappingList orgIdSystemIdMapping = clearingHelper.getOrgIdSystemIdMapping(keycloak);
if (orgIdSystemIdMapping != null)
orgIdSystemIdMapping.getContent().forEach(o -> organizationCacheRepository.saveOrgIdsSystemsIdsMappings(o.getOrgId(), o.getId()));
logger.debug("Was saved orgIds", orgIdSystemIdMapping.getContent().size());
catch (Exception e)
logger.error("Error fetching whole mapping for org and systems ids. Exception: ", e);
所以,在OrganizationCacheJob
的构建后阶段,我想在调用clearingHelper
时得到res
,但我得到的是null
。
ClearingHelper
是一个常规 Spring bean,使用公共方法标记为 @Component
。
【问题讨论】:
@Antoniossss 完成,请看一下。我认为 bean 本身的代码没什么大不了的,但如果你认为我也应该添加它 - 让我知道 :) 将doUpdateCacheRepository()
移动到构造函数并删除updateCacheRepository()
方法会发生什么?顺便说一句,你 don't need @Autowired
在构造函数上。
我在测试类代码中没有看到vdvClearingHelper
。也许这就是罪魁祸首。
你的意思是 clearingHelper 在 doUpdateCacheRepository() 方法中为空吗?
【参考方案1】:
啊,好吧,我刚刚意识到 - 当您开始测试用例时,整个环境首先启动并运行,然后您进入测试阶段。因此,转换为您的案例 - 首先您调用了注入和后构造,然后完成了 @Before
方法,从而得到了结果。
如您所见,代码比您在原始帖子中可以输入的所有单词都多。
如果可能,请使用间谍而不是模拟。如果无法构建它,您将不得不重新设计测试以不依赖 post 构建。
在这种情况下,由于您希望每个测试用例都具有相同的构造后行为,因此请为给定的模拟提供自己的工厂方法(就像您对 keycloak 所做的那样)并将 when-doReturn 移到那里。保证在后期构建之前发生。
【讨论】:
我最终为你所说的模拟提供了工厂方法,效果很好。谢谢!以上是关于在 Spring 的构建后阶段之前注入 mock的主要内容,如果未能解决你的问题,请参考以下文章
Autofac 集成测试 在 ConfigureContainer 之后进行 Mock 注入