Spring Boot测试报错:Failed to load ApplicationContext问题求助
问题描述
测试REST应用时遭遇错误,无法加载ApplicationContext,根源是无法用嵌入式数据库替换DataSource。
错误栈
java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:98) at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124) at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118) at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:43) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:248) at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:138) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:310) at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735) at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734) at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) at java.base/java.util.Optional.orElseGet(Optional.java:364) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Unsatisfied dependency expressed through method 'dataSourceScriptDatabaseInitializer' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Failed to replace DataSource with an embedded database for tests. If you want an embedded database please put a supported one on the classpath or tune the replace attribute of @AutoConfigureTestDatabase.
相关代码
测试类代码
@DataJpaTest @ActiveProfiles("test") public class SaveServiceTest { @Autowired private MedsRepo medsRepo; @Test void testSaveMeds() { Meds meds = new Meds(50, "test med", "5,00$", "Flu", 500, "test date"); Meds savedMed = medsRepo.save(meds); assertThat(savedMed).usingRecursiveComparison().ignoringFields("id").isEqualTo("meds"); } }
SaveService代码
@Service public class SaveService { @Autowired private MedsRepo medsRepo; public String saveMeds(@RequestBody Meds meds) { medsRepo.save(meds); return "Saved Successfully"; } }
MedsRepo代码
public interface MedsRepo extends JpaRepository<Meds,Long> { }
Meds实体类代码
@Data @AllArgsConstructor @NoArgsConstructor @Entity public class Meds { @Id @GeneratedValue(strategy = GenerationType.IDENTITY ) private long id; @Column private String name; @Column private String price; @Column private String category; @Column private int pillNumber; @Column private String date; }
控制器代码
@RestController public class Controller { @Autowired private MedsRepo medsRepo; @Autowired private SaveService saveService; @Autowired private UpdateService updateService; @Autowired DeleteService deleteService; @GetMapping("/medicines") public List<Meds> getMedicine(){ return medsRepo.findAll(); } @PostMapping(value = "/save") public String saveMeds(@RequestBody Meds meds){ return saveService.saveMeds(meds); } @PutMapping(value = "/update/{id}") public String updateMeds(@PathVariable long id, @RequestBody Meds meds){ return updateService.updateMeds(id, meds); } @DeleteMapping("/delete/{id}") public String deleteMeds(@PathVariable long id){ return deleteService.deleteMeds(id); } }
解决方案
方案1:添加嵌入式数据库依赖
@DataJpaTest默认会尝试用嵌入式数据库(如H2、HSQLDB)做测试,若项目未引入相关依赖就会报错。在构建文件中添加H2依赖:
Maven
<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>test</scope> </dependency>
Gradle
testImplementation 'com.h2database:h2'
方案2:关闭数据源自动替换
如果测试需要用外部数据库而非嵌入式库,给测试类添加@AutoConfigureTestDatabase注解调整策略:
@DataJpaTest @ActiveProfiles("test") @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) public class SaveServiceTest { // 原有测试代码不变 }
这样Spring Boot会直接使用test环境配置的数据源,不再尝试替换。
方案3:修正测试断言错误
测试类中的断言存在逻辑错误:isEqualTo("meds")是和字符串比较,实际应该和创建的meds对象比较,修改后:
assertThat(savedMed).usingRecursiveComparison().ignoringFields("id").isEqualTo(meds);
方案4:检查test环境配置
若已配置test环境数据源,确保application-test.properties/application-test.yml中的配置正确,且对应数据库驱动已引入依赖。例如MySQL配置:application-test.properties:
spring.datasource.url=jdbc:mysql://localhost:3306/test_db spring.datasource.username=root spring.datasource.password=your_password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
同时添加MySQL驱动依赖(Maven):
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
内容的提问来源于stack exchange,提问作者Bernardo Alves
相关产品推荐
相关产品推荐

