【问题标题】:How to properly run spock test using testcontainers in spring boot如何在 Spring Boot 中使用 testcontainers 正确运行 spock 测试
【发布时间】:2019-04-22 06:21:22
【问题描述】:

我有一个 Spring Boot 应用程序,使用 spocktestcontainers (mysql) 编写测试。我所做的工作正常,但感觉不对(因为@sql 用于每次测试迭代,所以我必须在我的 sql 脚本中使用INSERT IGNORE ...。我也不喜欢静态的技巧和非静态mysql容器)。 当谈到 testcontainers(实际上是 spock)时,我是一个完全的初学者,所以如果有人能告诉我如何使用 spock@sql、datasource 和 testcontainers 使其变得更好,我将不胜感激。

@SpringBootTest
@ContextConfiguration(initializers = Initializer.class)
@Testcontainers
class GeneratorTest extends Specification {

    public static MySQLContainer staticMySQLContainer = new MySQLContainer()
            .withDatabaseName("test")
            .withUsername("test")
            .withPassword("test")

    @Shared
    public MySQLContainer mySQLContainer = mySQLContainer;

    static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

        @Override
        void initialize(@NotNull ConfigurableApplicationContext configurableApplicationContext) {
            TestPropertyValues values = TestPropertyValues.of(
                    "spring.datasource.url=" + staticMySQLContainer.getJdbcUrl(),
                    "spring.datasource.password=" + staticMySQLContainer.getPassword(),
                    "spring.datasource.username=" + staticMySQLContainer.getUsername()
            )
            values.applyTo(configurableApplicationContext)
        }
    }

    @Autowired
    private CarService carService
    @Autowired
    private BikeRepository bikeRepository

    @Sql("/testdata/insert_into_cars.sql")
    def "validate number of doors"(int carId, int expectedNrOfDoors) {
        given:
        Car car = carService.getById(carId)

        expect:
        car.getNrOfDoors() == expectedNrOfDoors

        where:
        carId || expectedNrOfDoors
        1     || 3
        2     || 3
        3     || 5
    }
}

更新(使用基于JDBC的容器)
JDBC-based containers时,我不确定我是否正确设置。我在test/resources目录中创建了application-test.properties。我已经放在那里了:

spring.datasource.url=jdbc:tc:mysql:8.0.12://localhost:3306/shop?createDatabaseIfNotExist=true&serverTimezone=UTC
spring.datasource.username=test
spring.datasource.password=test
spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver

我的测试类看起来像:

@SpringBootTest
@Testcontainers
@TestPropertySource(locations="classpath:application-test.properties")
class GeneratorTest extends Specification {

    @Autowired
    private CarService carService

    <skipped for brevity>

当我尝试运行测试类时,我继续获得:

    2018-11-20 19:10:25.409 2612@DESKTOP-MLK30PF  INFO --- [main] ???? [mysql:8.0.12].waitUntilContainerStarted : Waiting for database connection to become available at jdbc:mysql://192.168.99.100:32770/shop using query 'SELECT 1' (JdbcDatabaseContainer.java:128) 
2018-11-20 19:12:25.420 2612@DESKTOP-MLK30PF ERROR --- [main] ???? [mysql:8.0.12].tryStart : Could not start container (GenericContainer.java:297) 
org.rnorth.ducttape.TimeoutException: org.rnorth.ducttape.TimeoutException: java.util.concurrent.TimeoutException
    at org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:53)
    at org.testcontainers.containers.JdbcDatabaseContainer.waitUntilContainerStarted(JdbcDatabaseContainer.java:129)
    at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:292)

紧随其后

2018-11-20 19:12:25.486 2612@DESKTOP-MLK30PF  INFO --- [tc-okhttp-stream-242833949] ???? [mysql:8.0.12].accept : STDERR: 2018-11-20T18:10:44.918132Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.12'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server - GPL. (Slf4jLogConsumer.java:32) 
2018-11-20 19:12:25.487 2612@DESKTOP-MLK30PF  INFO --- [main] ???? [mysql:8.0.12].tryStart : Creating container for image: mysql:8.0.12 (GenericContainer.java:253) 
2018-11-20 19:12:25.609 2612@DESKTOP-MLK30PF  INFO --- [main] ???? [mysql:8.0.12].tryStart : Starting container with ID: de75c9dafed8032b84cb827bf43a29c1964bfe4e168422272c9310a4803fd856 (GenericContainer.java:266) 
2018-11-20 19:12:25.896 2612@DESKTOP-MLK30PF  INFO --- [main] ???? [mysql:8.0.12].tryStart : Container mysql:8.0.12 is starting: de75c9dafed8032b84cb827bf43a29c1964bfe4e168422272c9310a4803fd856 (GenericContainer.java:273) 
2018-11-20 19:12:25.901 2612@DESKTOP-MLK30PF  INFO --- [main] ???? [mysql:8.0.12].waitUntilContainerStarted : Waiting for database connection to become available at jdbc:mysql://192.168.99.100:32772/shop using query 'SELECT 1' (JdbcDatabaseContainer.java:128) 

对于mysql版本8 look here

更新(已解决):
正如@bsideup 指出的那样,基于 jdbc 的容器是此用例的最佳解决方案。正如我在上面描述的那样,它工作得非常好,但我不得不将 mysql 版本从8 更改为更低。

【问题讨论】:

    标签: spock spring-boot-test testcontainers


    【解决方案1】:

    你试过JDBC-based containers吗?

    【讨论】:

    • 好点,还是有些麻烦,可能是配置错误,我已经更新了我的帖子如果你想看看,谢谢。
    • 它不适用于版本8。建议使用--default-authentication-plugin=mysql_native_password。是否可以传入基于 jdbc 的容器? github.com/testcontainers/testcontainers-java/issues/736
    • 现在可以使用了,从 Testcontainers 1.11.4 开始 :)
    【解决方案2】:

    你可以的

    def setupSpec(){ //or use setup(){ if not a @Shared Container
    System.getProperties()
                        .putAll([
                                "spring.datasource.url"     : mySQLContainer...,
                                "spring.datasource.username": mySQLContainer...,
                                "spring.datasource.password": mySQLContainer...
                        ])
    }
    

    那么你就可以摆脱 staticMySQLContainer

    还有初始化器

    【讨论】:

      猜你喜欢
      • 2019-01-27
      • 2022-06-14
      • 1970-01-01
      • 2021-07-23
      • 2018-01-27
      • 2014-08-15
      • 2016-07-16
      • 2016-12-22
      • 2017-06-28
      相关资源
      最近更新 更多