如何使用Mockito Mock Spring中通过@Value结合SpEL表达式注入的Map对象
嘿,这个场景我熟!给你分享几种在Spring里用Mockito(配合Spring测试工具)Mock @Value注入的Map的实用方案,按需选就行:
方案1:纯单元测试——用ReflectionTestUtils直接赋值(最快最直接)
如果只是想单独测试目标类,不需要加载Spring上下文,用Mockito的@InjectMocks创建实例,再通过Spring的ReflectionTestUtils把我们自定义的Map直接塞进私有字段里就行:
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.util.ReflectionTestUtils; import java.util.HashMap; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; @ExtendWith(MockitoExtension.class) public class PatientServiceTest { @InjectMocks private PatientService patientService; // 你的目标业务类 @Test void testGetPatientTypeCode() { // 构建测试用的Map数据 Map<String, Integer> testPatientTypes = new HashMap<>(); testPatientTypes.put("ADULT", 1); testPatientTypes.put("CHILD", 2); // 直接给私有字段赋值 ReflectionTestUtils.setField(patientService, "patientTypes", testPatientTypes); // 验证业务逻辑 assertEquals(1, patientService.getPatientTypeCode("ADULT")); assertEquals(2, patientService.getPatientTypeCode("CHILD")); } }
方案2:Spring集成测试——用@TestPropertySource指定属性值
如果你的测试需要加载完整的Spring上下文(比如集成测试),直接在测试类上用@TestPropertySource配置属性,Spring会自动把解析后的Map注入到目标类:
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.TestPropertySource; import static org.junit.jupiter.api.Assertions.assertEquals; @SpringBootTest @TestPropertySource(properties = { "patientTypes.ADULT=1", "patientTypes.CHILD=2" }) public class PatientServiceIntegrationTest { @Autowired private PatientService patientService; @Test void testGetPatientTypeCode() { assertEquals(1, patientService.getPatientTypeCode("ADULT")); assertEquals(2, patientService.getPatientTypeCode("CHILD")); } }
这里要注意,你用的@Value("#{${patientTypes}}")是SpEL表达式,Spring会自动把patientTypes.*格式的属性解析成Map,直接写键值对就行。
方案3:复杂场景——自定义PropertySourcesPlaceholderConfigurer
如果需要在多个测试中复用这套Map配置,或者有更复杂的属性逻辑,可以自定义一个测试配置类,提供自定义的属性源:
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; @SpringBootTest public class PatientServiceComplexTest { @Autowired private PatientService patientService; // 测试专属配置类 @Configuration static class TestConfig { @Bean @Primary public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer(); // 直接设置解析后的Map Map<String, Object> testProperties = Map.of( "patientTypes", Map.of("ADULT", 1, "CHILD", 2) ); PropertySource<?> propertySource = new MapPropertySource("testProps", testProperties); configurer.getPropertySources().addFirst(propertySource); return configurer; } } @Test void testGetPatientTypeCode() { assertEquals(1, patientService.getPatientTypeCode("ADULT")); assertEquals(2, patientService.getPatientTypeCode("CHILD")); } }
小提醒
- 方案1是纯单元测试,不加载Spring上下文,执行速度最快,适合单类独立测试。
- 方案2和3需要加载Spring上下文,适合需要依赖其他Spring Bean的集成测试场景。
ReflectionTestUtils是spring-test包提供的工具类,确保你的测试依赖里包含这个包。
内容的提问来源于stack exchange,提问作者PAA
相关产品推荐
相关产品推荐

