【问题标题】:How to inject parameter value into bean during test execution?如何在测试执行期间将参数值注入bean?
【发布时间】:2026-02-08 11:30:01
【问题描述】:

Car 类构造函数中,我使用@Value 注解将值作为参数注入。

@Service
public class Car {
  
   public Car(@Value("${app.fabric.kafka.topics.sometopic}") final String topic) {
   }
   ...    
}

GarageService 类声明并使用Car 实例。

@Component
@AllArgsConstructor
public class GarageService {
    
    private @NonNull final Car; 
 ...
} 

GarageServiceTest 类中,我使用@InjectMock 实例化测试对象并使用@Mock 注入另一个实例。

@ContextConfiguration
public class GarageServiceTest {
    @Mock private CarService carService; 
    @InjectMock private GarageService;
    ...
}

这个类中的测试给出了一个异常:

org.springframework.beans.factory.UnsatisfiedDependencyException:
Error when creating bean 'GarageService' defined in file [.../GarageService.class]:
Unsatisfied dependency expressed through constructor parameter 1, 
...
nested exception is org.springframework.beans.factory.BenCreationException: 
Error creating bean with name 'Car' defined in file [.../Car.class]: Unexpected exception during bean 
creation; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 
app.fabric.kafka.topics.sometopic' in value "${app.fabric.kafka.topics.sometopic}".

问题如何解决这个异常?我的理解是,在那个测试类中,我需要找到一种方法将${app.fabric.kafka.topics.sometopic}" 值注入 bean `Car'。

【问题讨论】:

  • 这应该是一个 unit 测试还是更全面的基于 Spring 的功能测试?你在混合风格。
  • 这只是从更复杂的代码中提取的高级内容。它的单元测试。它在一个依赖于另一个实例的类中测试方法。
  • 所以?使用构造函数注入的主要优点之一是您可以调用new ServiceUnderTest(mockDependency, string)

标签: java spring mockito junit5


【解决方案1】:

我了解到您正在使用 Spring 扩展程序运行测试。这意味着 Spring 将为您的测试初始化​​一个 ApplicationContext。显然,在初始化期间,app.fabric.kafka.topics.sometopic 由于某种原因不可用。

这个初始化和Mockito的@Mock/@InjectMocks注解无关。如果您想测试 GarageService Spring bean,并模拟 CarService,请尝试以下操作:

public class GarageServiceTest {
    @MockBean private CarService carService; 
    @Autowired private GarageService;
    ...
}

如果您想要一个单元测试,其中 GarageService 被创建为常规对象,请不要将 @RunWih(SpringRunner.class)/@ExtendWith(SpringExtension.class) 用于此特定测试。

如果您在其他测试中遇到同样的问题,其中 CarService 应该被模拟,使用 @TestPropertySource(properties = "app.fabric.kafka.topics.sometopic=<whatever works>")@SpringBootTest(properties = "app.fabric.kafka.topics.sometopic=<whatever works>") 如果使用 Spring Boot。

【讨论】:

    【解决方案2】:

    如果你想避免巨大的弹簧上下文:

    @Data
    @AllArgsConstructor
    class Car {
        @Value("${app.fabric.kafka.topics.sometopic}")
        private String topic;
    }
    
    @Data
    @AllArgsConstructor
    class GarageService {
        private final Car car;
    }
    
    @RunWith(MockitoJUnitRunner.class)
    public class dd {
        String topic = "topic";
        @Mock Car car;
        @InjectMocks GarageService garageService;
    
        @Test
        public void test() {
            when(car.getTopic()).thenReturn(topic);
            System.out.println(car.getTopic()); // topic
        }
    }
    

    【讨论】: