GitHub Actions中Kotlin Spring Boot+MySQL集成测试连接异常排查
问题描述
我正在为一个Kotlin开发、Gradle构建、使用MySQL数据库的Spring Boot项目创建GitHub Actions工作流,用于运行集成测试。但执行构建测试步骤(运行./gradlew clean build)时,所有测试都失败,错误栈如下:
Caused by: java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:98 Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1804 Caused by: javax.persistence.PersistenceException at AbstractEntityManagerFactoryBean.java:421 Caused by: org.hibernate.exception.JDBCConnectionException at SQLStateConversionDelegate.java:112 Caused by: com.mysql.cj.jdbc.exceptions.CommunicationsException at SQLError.java:174 Caused by: com.mysql.cj.exceptions.CJCommunicationsException at NativeConstructorAccessorImpl.java:-2 Caused by: java.net.ConnectException at PlainSocketImpl.java:-2
我的gradle.yml配置:
name: CI with Gradle on: [push] permissions: contents: read jobs: build: runs-on: ubuntu-latest container: openjdk:11 services: mysql: image: mysql:latest steps: - uses: actions/checkout@v3 - name: Set up JDK 11 uses: actions/setup-java@v3 with: java-version: '11' distribution: 'temurin' - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build & Test with Gradle uses: gradle/gradle-build-action@v2 with: arguments: build
application.properties配置:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/wct?useSSL=true&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=pw spring.jpa.hibernate.ddl-auto=update spring.jpa.database=mysql server.port=8081
失败的JUnit测试示例:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) internal class CustomerControllerTests( @Autowired val context: WebApplicationContext, @Autowired val mapper: ObjectMapper, @Autowired val customerRepository: CustomerRepository, ) { private val mvc: MockMvc = (MockMvcBuilders.webAppContextSetup(context).apply<DefaultMockMvcBuilder>( SecurityMockMvcConfigurers.springSecurity()).build()) @Test fun `GET customers should return an empty list of customers and 200 OK if one of the required roles is provided`() { val response = mvc.perform( MockMvcRequestBuilders.get("/customers") .contentType(MediaType.APPLICATION_JSON) ).andExpect(MockMvcResultMatchers.status().isOk).andReturn().response response.contentLength shouldBe 0 } }
请问哪里操作有误或遗漏了什么?
问题原因及解决方案
1. GitHub Actions MySQL服务配置不完整
当前的MySQL服务仅指定了镜像,缺少必要的初始化配置和健康检查,导致Spring Boot启动时MySQL还未就绪,且无法通过localhost访问服务。
修正后的MySQL服务配置:
在gradle.yml的services.mysql节点添加环境变量、端口映射和健康检查:
services: mysql: image: mysql:latest env: MYSQL_ROOT_PASSWORD: pw # 和数据库配置中的密码保持一致 MYSQL_DATABASE: wct # 提前创建测试所需的数据库 ports: - 3306:3306 options: >- --health-cmd="mysqladmin ping -h localhost" --health-interval=10s --health-timeout=5s --health-retries=3
2. 数据库连接配置错误
GitHub Actions的container模式下,服务容器和Job容器通过服务名通信,而非localhost;同时MySQL默认环境下无需SSL连接(或需额外证书配置),需修改数据库连接配置:
推荐使用测试专用配置文件
创建src/test/resources/application-test.properties,单独配置测试环境的数据库参数:
spring.datasource.url=jdbc:mysql://mysql:3306/wct?useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=pw spring.jpa.hibernate.ddl-auto=create-drop # 测试结束自动清理数据库,避免脏数据残留
3. 等待MySQL服务完全就绪
在Gradle构建步骤前添加等待逻辑,确保数据库服务完全启动后再执行测试:
在gradle.yml的steps中插入:
- name: Wait for MySQL to be ready run: | until mysqladmin ping -h mysql -u root -ppw --silent; do echo "Waiting for MySQL service..." sleep 2 done shell: bash
修正后的完整gradle.yml
name: CI with Gradle on: [push] permissions: contents: read jobs: build: runs-on: ubuntu-latest container: openjdk:11 services: mysql: image: mysql:latest env: MYSQL_ROOT_PASSWORD: pw MYSQL_DATABASE: wct ports: - 3306:3306 options: >- --health-cmd="mysqladmin ping -h localhost" --health-interval=10s --health-timeout=5s --health-retries=3 steps: - uses: actions/checkout@v3 - name: Set up JDK 11 uses: actions/setup-java@v3 with: java-version: '11' distribution: 'temurin' - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Wait for MySQL to be ready run: | until mysqladmin ping -h mysql -u root -ppw --silent; do echo "Waiting for MySQL service..." sleep 2 done shell: bash - name: Build & Test with Gradle uses: gradle/gradle-build-action@v2 with: arguments: build
内容的提问来源于stack exchange,提问作者John Adams
相关产品推荐
相关产品推荐

