sky*_*yho 5 postgresql integration-testing docker spring-boot testcontainers
当我尝试逐一运行测试时遇到问题。\n数据库连接已关闭。
\n根据文档(声明为静态字段的容器...),我试图确保我的容器在所有测试中都被引发一次。
\n我专门使用它来获得Spring的应用程序上下文和一次引发并用于所有测试的测试容器。
\n确实如此,因为我在每个测试中都会进行检查:
\n boolean running = getPostgreSQLContainer().isRunning();\n\n System.out.println(running);\nRun Code Online (Sandbox Code Playgroud)\n也就是说,测试是一项一项自动运行的。
\n <parent>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-starter-parent</artifactId>\n <version>2.4.1</version>\n <relativePath/> <!-- lookup parent from repository -->\n </parent>\n\n....\n\n<properties>\n <java.version>11</java.version>\n <testcontainers.version>1.15.1</testcontainers.version>\n <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n <version.mapstruct>1.4.1.Final</version.mapstruct>\n <version.maven.compiler.plugin>3.8.1</version.maven.compiler.plugin>\n <version.embedded.postgresql.testcontainers>1.86</version.embedded.postgresql.testcontainers>\n <version.spring.cloud.starter>2.2.6.RELEASE</version.spring.cloud.starter>\n </properties>\n\n <dependencies>\n <dependency>\n <groupId>org.testcontainers</groupId>\n <artifactId>postgresql</artifactId>\n <scope>test</scope>\n </dependency>\n\n <dependency>\n <groupId>org.mapstruct</groupId>\n <artifactId>mapstruct</artifactId>\n <version>${version.mapstruct}</version>\n </dependency>\n\n <dependency>\n <groupId>org.mapstruct</groupId>\n <artifactId>mapstruct-processor</artifactId>\n <version>${version.mapstruct}</version>\n <scope>provided</scope>\n </dependency>\n\n <dependency>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-starter-data-jpa</artifactId>\n </dependency>\n <dependency>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-starter-data-rest</artifactId>\n </dependency>\n <dependency>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-starter-web</artifactId>\n </dependency>\n\n <dependency>\n <groupId>org.liquibase</groupId>\n <artifactId>liquibase-core</artifactId>\n </dependency>\n\n <dependency>\n <groupId>org.postgresql</groupId>\n <artifactId>postgresql</artifactId>\n <scope>runtime</scope>\n </dependency>\n\n <dependency>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-starter</artifactId>\n </dependency>\n\n <dependency>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-starter-test</artifactId>\n <scope>test</scope>\n </dependency>\n\n <dependency>\n <groupId>org.testcontainers</groupId>\n <artifactId>junit-jupiter</artifactId>\n <scope>test</scope>\n </dependency>\n\n </dependencies>\n\n <dependencyManagement>\n <dependencies>\n <dependency>\n <groupId>org.testcontainers</groupId>\n <artifactId>testcontainers-bom</artifactId>\n <version>${testcontainers.version}</version>\n <type>pom</type>\n <scope>import</scope>\n </dependency>\n </dependencies>\n </dependencyManagement>\n\n <build>\n <plugins>\n <plugin>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-maven-plugin</artifactId>\n </plugin>\n </plugins>\n </build>\nRun Code Online (Sandbox Code Playgroud)\n@Testcontainers\n@TestPropertySource("classpath:application.properties")\npublic class TestPostgresContainer {\n\n private static String dataBaseName;\n private static String userNameBase;\n private static String passwordBase;\n\n public TestPostgresContainer() {\n }\n\n private static DockerImageName postgres;\n\n static {\n postgres = DockerImageName.parse("postgres:13.1");\n dataBaseName = PropertiesExtractor.getProperty("database.name.test.container");\n userNameBase = PropertiesExtractor.getProperty("username.testcontainer");\n passwordBase = PropertiesExtractor.getProperty("password.testcontainer");\n }\n\n @SuppressWarnings("rawtypes")\n @Container\n private static PostgreSQLContainer postgreSQLContainer = (PostgreSQLContainer) new PostgreSQLContainer(postgres)\n .withDatabaseName(dataBaseName)\n .withUsername(userNameBase)\n .withPassword(passwordBase)\n .withStartupTimeout(Duration.ofSeconds(600));\n\n\n @SuppressWarnings("rawtypes")\n public static PostgreSQLContainer getPostgreSQLContainer() {\n return postgreSQLContainer;\n }\n\n /**\n * It need for Spring boot 2.2.6 and higher.\n */\n @DynamicPropertySource\n static void properties(DynamicPropertyRegistry propertyRegistry){\n\n propertyRegistry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl);\n propertyRegistry.add("spring.datasource.username", postgreSQLContainer::getUsername);\n propertyRegistry.add("spring.datasource.password", postgreSQLContainer::getPassword);\n }\n\nRun Code Online (Sandbox Code Playgroud)\n\n@RunWith(SpringRunner.class)\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\npublic class TestcontainersSpringBootClassruleApplicationTests extends TestPostgresContainer {\n\n @Autowired\n protected TestRestTemplate testRestTemplate;\n\n\n @Test\n @DisplayName("Should start the container")\n public void test() {\n\n boolean running = getPostgreSQLContainer().isRunning();\n\n System.out.println(running);\n }\n}\nRun Code Online (Sandbox Code Playgroud)\nclass EmployeeRestControllerTest extends TestcontainersSpringBootClassruleApplicationTests {\n\n private static EmployeeDto employeeDto;\n\n @BeforeAll\n static void createUser(){\n\n PostgreSQLContainer postgreSQLContainer = getPostgreSQLContainer();\n\n employeeDto = EmployeeDto\n .newBuilder()\n .firstName("Joanna")\n .lastName("Soyer")\n .country("germany")\n .build();\n }\n\n @Transactional\n @Test\n void addEmployee() {\n boolean running = getPostgreSQLContainer().isRunning();\n\n System.out.println(running);\n\n String url = "/employees/addEmployee";\n\n HttpEntity<EmployeeDto> entity = new HttpEntity<>(employeeDto);\n\n ResponseEntity<EmployeeDto> employeeDtoResponseEntity =\n testRestTemplate.exchange(url, HttpMethod.POST, entity, EmployeeDto.class);\n\n HttpStatus statusCode = employeeDtoResponseEntity.getStatusCode();\n assertThat(statusCode, is(HttpStatus.OK));\n }\n\n @Test\n void getAllEmployees() {\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n测试类位于不同的目录中
\nspring.main.banner-mode=off\nspring.datasource.initialization-mode=always\n\n## PostgreSQL for TestContainers\ndatabase.name.test.container=integration-tests-db\nusername.testcontainer=root\npassword.testcontainer=root\n\nspring.datasource.hikari.max-life = 600000 \n\nspring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true\n\nspring.liquibase.change-log=classpath:/db/changelog/db.changelog-master-test.xml\nRun Code Online (Sandbox Code Playgroud)\n我用的是liquibase。
\nWnen 正在运行所有测试:
\n\n\ncom.zaxxer.hikari.pool.PoolBase :HikariPool-1 - 无法验证连接 org.postgresql.jdbc.PgConnection@698af960 (\xd0\xa1\xd0\xbe\xd0\xb5\xd0\xb4\xd0\xb8\xd0 \xbd\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb5 \xd1\x83\xd0\xb6\xd0\xb5 \xd0\xb1\xd1\x8b\xd0\xbb\xd0\xbe \xd0\xb7 \xd0\xb0\xd0\xba\xd1\x80\xd1\x8b\xd1\x82\xd0\xbe)。可能考虑使用较短的 maxLifetime 值。
\n
我设置了一个值
\nspring.main.banner-mode=off\nspring.datasource.initialization-mode=always\n\n## PostgreSQL for TestContainers\ndatabase.name.test.container=integration-tests-db\nusername.testcontainer=root\npassword.testcontainer=root\n\nspring.datasource.hikari.max-life = 600000 \n\nspring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true\n\nspring.liquibase.change-log=classpath:/db/changelog/db.changelog-master-test.xml\nRun Code Online (Sandbox Code Playgroud)\n这没有帮助。
\n但是当我一次运行一个测试类时,就没有错误了。
\n我找到了这个:
\n\n\n在守护程序模式下运行容器\n默认情况下,数据库容器在最后一个连接关闭后立即停止。在某些情况下,您可能需要启动容器并保持其运行,直到您显式停止它或 JVM 关闭。为此,请将 TC_DAEMON 参数添加到 URL,如下所示:
\njdbc:tc:mysql:5.7.22:///数据库名称?TC_DAEMON=true
\n
但是,我可以在哪里添加TC_DAEMON=true?
\n我不直接指定 url 本身。它是由 TestContainers 完成的。
\n使用此参数,即使没有打开的连接,数据库容器也将继续运行。
\n我编辑了这个:
\nspring.datasource.hikari.max-life = 600000\nRun Code Online (Sandbox Code Playgroud)\n@Container\n private static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer(postgres)\n .withDatabaseName(dataBaseName)\n .withUsername(userNameBase)\n .withPassword(passwordBase);\nRun Code Online (Sandbox Code Playgroud)\n这也没有帮助。
\n我已经没有主意了。
\n有谁知道如何解决这个问题?
\n您正在使用 JUnit Jupiter 扩展 ( @Testcontainers) 来控制容器的生命周期。该扩展支持两种模式:
因此,对于您的设置,Testcontaienrs 会为每个测试类启动一个数据库,该数据库不在多个测试类之间共享,而是在同一测试类中共享测试方法。
由于您的问题中存在所有代码层次结构和代码更新,因此很难说问题来自何处。
如果您想重用数据库容器并且只启动一次,请查看 Singleton 容器和可重用性功能。
PS:您不需要,@RunWith(SpringRunner.class)因为您正在使用 JUnit 5 运行测试,并且 JUnit Jupiter 扩展 ( SpringExtension) 已注册为@SpringBootTest
| 归档时间: |
|
| 查看次数: |
10317 次 |
| 最近记录: |