Spring 使用 testcontainers 启动并且 jOOQ 不注入 DSL 上下文
Spring boot with testcontainers and jOOQ doesn't inject DSL context
我在使用 spring boot + jOOQ 和 testcontainers 时遇到了一些问题。 DSL 上下文不会在我的测试中注入 class.
我为使用做了一些准备SQLContainer
class SpringTestContainer: PostgreSQLContainer<SpringTestContainer> {
private val postgreSqlPort = 5432
private val db = "m4"
companion object {
var instance: SpringTestContainer? = null
fun get(): SpringTestContainer {
if(instance == null) {
instance = SpringTestContainer()
}
return instance!!
}
}
override fun getDatabaseName(): String = db
constructor() : this("registry.dev.tskad.stdev.ru/m4/db:latest")
constructor(dockerImageName: String) : super(dockerImageName){
withImagePullPolicy(PullPolicy.alwaysPull())
addExposedPort(postgreSqlPort)
waitStrategy = LogMessageWaitStrategy()
.withRegEx(".*database system is ready to accept connections.*\s")
.withTimes(1)
.withStartupTimeout(Duration.of(30, ChronoUnit.SECONDS))
}
override fun getJdbcUrl(): String {
return String.format("jdbc:postgresql://%s:%d/%s", containerIpAddress, getMappedPort(postgreSqlPort), databaseName)
}
override fun waitUntilContainerStarted() {
getWaitStrategy().waitUntilReady(this)
}
override fun getLivenessCheckPorts(): Set<Int?> {
return HashSet(getMappedPort(postgreSqlPort))
}
}
然后我创建了一些抽象来扩展我的集成测试 classes
@ContextConfiguration(initializers = [SpringIntegrationTest.Initializer::class])
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@JooqTest
abstract class SpringIntegrationTest {
@get:Rule
var postgreSQLContainer = SpringTestContainer.get()
inner class Initializer: ApplicationContextInitializer<ConfigurableApplicationContext> {
override fun initialize(applicationContext: ConfigurableApplicationContext) {
with(applicationContext.environment.systemProperties) {
put("spring.datasource.url", postgreSQLContainer.jdbcUrl)
put("spring.datasource.username", postgreSQLContainer.username)
put("spring.datasource.password", postgreSQLContainer.password)
}
}
}
}
然后我实施了测试class
@ExtendWith(SpringExtension::class)
class TransactionRepositoryImplTest: SpringIntegrationTest() {
@Autowired
private var dslContext: DSLContext? = null
private var transactionRepository: TransactionRepository? = null
@Before
fun setUp() {
assertThat(dslContext).isNotNull
transactionRepository = TransactionRepositoryImpl(dslContext!!)
}
@After
fun tearDown() {
}
@Test
fun findTransactionData() {
transactionRepository?.findTransactionByVehicleUuid(null).apply {
assertNull(this)
}
}
}
当我开始测试这个 class - 测试失败,因为断言没有通过。
这是测试报告 https://pastebin.com/0HeqDcCT
所以..怎么不可能?我看到了一些关于这个堆栈的指南(Spring/jOOQ/TestContainers)。他们都在工作。也许我错过了一些测试依赖项?如果您对这种情况有经验 - 请分享您的解决方案。我将不胜感激。
dependencies {
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.springframework.boot:spring-boot-starter-jooq")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.cloud:spring-cloud-starter-consul-config")
implementation("org.springframework.cloud:spring-cloud-stream")
implementation("org.springframework.cloud:spring-cloud-stream-binder-kafka")
implementation("org.springframework.kafka:spring-kafka")
implementation("org.springframework.boot:spring-boot-starter-amqp")
implementation ("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.3")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.10.3")
runtimeOnly("org.postgresql:postgresql:42.2.12")
jooqGeneratorRuntime("org.postgresql:postgresql:42.2.12")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
exclude(module = "junit")
}
testImplementation("com.ninja-squad:springmockk:2.0.1")
testImplementation("org.springframework.cloud:spring-cloud-stream-test-support")
testImplementation("org.springframework.kafka:spring-kafka-test")
testImplementation("org.springframework.amqp:spring-rabbit-test")
testImplementation("org.testcontainers:postgresql:1.14.3")
}
我可能遗漏了一些东西,但在该设置中,您必须手动 运行
postgreSQLContainer.start()
某处。例如,它可以在 @BeforeAll
.
中完成
我找到了解决办法。正确的方法是覆盖测试容器实现的 start
方法并将系统属性放入容器数据库的凭据。
这是工作代码:
class SpringTestContainer: PostgreSQLContainer<SpringTestContainer> {
private val postgreSqlPort = 5432
private val db = "m4"
companion object {
var instance: SpringTestContainer? = null
fun get(): SpringTestContainer {
if(instance == null) {
instance = SpringTestContainer()
}
return instance!!
}
}
override fun getDatabaseName(): String = db
constructor() : this("registry.dev.tskad.stdev.ru/m4/db:latest")
constructor(dockerImageName: String) : super(dockerImageName){
withImagePullPolicy(PullPolicy.alwaysPull())
addExposedPort(postgreSqlPort)
waitStrategy = LogMessageWaitStrategy()
.withRegEx(".*database system is ready to accept connections.*\s")
.withTimes(1)
.withStartupTimeout(Duration.of(30, ChronoUnit.SECONDS))
}
override fun getJdbcUrl(): String {
return String.format("jdbc:postgresql://%s:%d/%s", containerIpAddress, getMappedPort(postgreSqlPort), databaseName)
}
override fun waitUntilContainerStarted() {
getWaitStrategy().waitUntilReady(this)
}
override fun getLivenessCheckPorts(): Set<Int?> {
return HashSet(getMappedPort(postgreSqlPort))
}
override fun start() {
super.start()
val container = get()
System.setProperty("DB_URL", container.jdbcUrl)
System.setProperty("DB_USERNAME", container.username)
System.setProperty("DB_PASSWORD", container.password)
}
}
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@SpringBootTest(properties = ["spring.cloud.consul.enabled = false"])
@EnableAutoConfiguration(exclude = [
RabbitAutoConfiguration::class,
KafkaAutoConfiguration::class
])
class TransactionRepositoryImplTest {
@get:Rule
var postgreSQLContainer = SpringTestContainer.get()
@Autowired
private lateinit var dslContext: DSLContext
@Autowired
private lateinit var transactionRepository: TransactionRepository
@MockkBean
private lateinit var connectionFactory: ConnectionFactory // this is the mock for rabbit connection. U may ignore it.
@Test
fun contextLoads() {
Assertions.assertNotNull(dslContext)
Assertions.assertNotNull(transactionRepository)
}
}
然后需要在测试目录
中修复application.yml
spring:
datasource:
platform: postgres
url: ${DB_URL}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
driverClassName: org.postgresql.Driver
我在使用 spring boot + jOOQ 和 testcontainers 时遇到了一些问题。 DSL 上下文不会在我的测试中注入 class.
我为使用做了一些准备SQLContainer
class SpringTestContainer: PostgreSQLContainer<SpringTestContainer> {
private val postgreSqlPort = 5432
private val db = "m4"
companion object {
var instance: SpringTestContainer? = null
fun get(): SpringTestContainer {
if(instance == null) {
instance = SpringTestContainer()
}
return instance!!
}
}
override fun getDatabaseName(): String = db
constructor() : this("registry.dev.tskad.stdev.ru/m4/db:latest")
constructor(dockerImageName: String) : super(dockerImageName){
withImagePullPolicy(PullPolicy.alwaysPull())
addExposedPort(postgreSqlPort)
waitStrategy = LogMessageWaitStrategy()
.withRegEx(".*database system is ready to accept connections.*\s")
.withTimes(1)
.withStartupTimeout(Duration.of(30, ChronoUnit.SECONDS))
}
override fun getJdbcUrl(): String {
return String.format("jdbc:postgresql://%s:%d/%s", containerIpAddress, getMappedPort(postgreSqlPort), databaseName)
}
override fun waitUntilContainerStarted() {
getWaitStrategy().waitUntilReady(this)
}
override fun getLivenessCheckPorts(): Set<Int?> {
return HashSet(getMappedPort(postgreSqlPort))
}
}
然后我创建了一些抽象来扩展我的集成测试 classes
@ContextConfiguration(initializers = [SpringIntegrationTest.Initializer::class])
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@JooqTest
abstract class SpringIntegrationTest {
@get:Rule
var postgreSQLContainer = SpringTestContainer.get()
inner class Initializer: ApplicationContextInitializer<ConfigurableApplicationContext> {
override fun initialize(applicationContext: ConfigurableApplicationContext) {
with(applicationContext.environment.systemProperties) {
put("spring.datasource.url", postgreSQLContainer.jdbcUrl)
put("spring.datasource.username", postgreSQLContainer.username)
put("spring.datasource.password", postgreSQLContainer.password)
}
}
}
}
然后我实施了测试class
@ExtendWith(SpringExtension::class)
class TransactionRepositoryImplTest: SpringIntegrationTest() {
@Autowired
private var dslContext: DSLContext? = null
private var transactionRepository: TransactionRepository? = null
@Before
fun setUp() {
assertThat(dslContext).isNotNull
transactionRepository = TransactionRepositoryImpl(dslContext!!)
}
@After
fun tearDown() {
}
@Test
fun findTransactionData() {
transactionRepository?.findTransactionByVehicleUuid(null).apply {
assertNull(this)
}
}
}
当我开始测试这个 class - 测试失败,因为断言没有通过。 这是测试报告 https://pastebin.com/0HeqDcCT
所以..怎么不可能?我看到了一些关于这个堆栈的指南(Spring/jOOQ/TestContainers)。他们都在工作。也许我错过了一些测试依赖项?如果您对这种情况有经验 - 请分享您的解决方案。我将不胜感激。
dependencies {
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.springframework.boot:spring-boot-starter-jooq")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.cloud:spring-cloud-starter-consul-config")
implementation("org.springframework.cloud:spring-cloud-stream")
implementation("org.springframework.cloud:spring-cloud-stream-binder-kafka")
implementation("org.springframework.kafka:spring-kafka")
implementation("org.springframework.boot:spring-boot-starter-amqp")
implementation ("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.3")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.10.3")
runtimeOnly("org.postgresql:postgresql:42.2.12")
jooqGeneratorRuntime("org.postgresql:postgresql:42.2.12")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
exclude(module = "junit")
}
testImplementation("com.ninja-squad:springmockk:2.0.1")
testImplementation("org.springframework.cloud:spring-cloud-stream-test-support")
testImplementation("org.springframework.kafka:spring-kafka-test")
testImplementation("org.springframework.amqp:spring-rabbit-test")
testImplementation("org.testcontainers:postgresql:1.14.3")
}
我可能遗漏了一些东西,但在该设置中,您必须手动 运行
postgreSQLContainer.start()
某处。例如,它可以在 @BeforeAll
.
我找到了解决办法。正确的方法是覆盖测试容器实现的 start
方法并将系统属性放入容器数据库的凭据。
这是工作代码:
class SpringTestContainer: PostgreSQLContainer<SpringTestContainer> {
private val postgreSqlPort = 5432
private val db = "m4"
companion object {
var instance: SpringTestContainer? = null
fun get(): SpringTestContainer {
if(instance == null) {
instance = SpringTestContainer()
}
return instance!!
}
}
override fun getDatabaseName(): String = db
constructor() : this("registry.dev.tskad.stdev.ru/m4/db:latest")
constructor(dockerImageName: String) : super(dockerImageName){
withImagePullPolicy(PullPolicy.alwaysPull())
addExposedPort(postgreSqlPort)
waitStrategy = LogMessageWaitStrategy()
.withRegEx(".*database system is ready to accept connections.*\s")
.withTimes(1)
.withStartupTimeout(Duration.of(30, ChronoUnit.SECONDS))
}
override fun getJdbcUrl(): String {
return String.format("jdbc:postgresql://%s:%d/%s", containerIpAddress, getMappedPort(postgreSqlPort), databaseName)
}
override fun waitUntilContainerStarted() {
getWaitStrategy().waitUntilReady(this)
}
override fun getLivenessCheckPorts(): Set<Int?> {
return HashSet(getMappedPort(postgreSqlPort))
}
override fun start() {
super.start()
val container = get()
System.setProperty("DB_URL", container.jdbcUrl)
System.setProperty("DB_USERNAME", container.username)
System.setProperty("DB_PASSWORD", container.password)
}
}
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@SpringBootTest(properties = ["spring.cloud.consul.enabled = false"])
@EnableAutoConfiguration(exclude = [
RabbitAutoConfiguration::class,
KafkaAutoConfiguration::class
])
class TransactionRepositoryImplTest {
@get:Rule
var postgreSQLContainer = SpringTestContainer.get()
@Autowired
private lateinit var dslContext: DSLContext
@Autowired
private lateinit var transactionRepository: TransactionRepository
@MockkBean
private lateinit var connectionFactory: ConnectionFactory // this is the mock for rabbit connection. U may ignore it.
@Test
fun contextLoads() {
Assertions.assertNotNull(dslContext)
Assertions.assertNotNull(transactionRepository)
}
}
然后需要在测试目录
中修复application.yml
spring:
datasource:
platform: postgres
url: ${DB_URL}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
driverClassName: org.postgresql.Driver