使用 SpringBootTest 的 TestContainers 中的 DB 容器出现问题
Posted
技术标签:
【中文标题】使用 SpringBootTest 的 TestContainers 中的 DB 容器出现问题【英文标题】:Problem with DB container in TestContainers using SpringBootTest 【发布时间】:2019-05-09 22:48:23 【问题描述】:我有一个使用 TestContainers 的抽象类 BaseIntegrationTest。问题是当我尝试运行像 UserRepositoryIntSpec 这样的简单数据库测试时,我遇到了一个异常,这意味着计数从 114 开始,而不是像预期的那样从 1 开始。为什么索引不是从 1 开始?为什么每次执行设置时我的本地数据库用户表都很清楚,因为我希望测试在容器中使用容器数据库运行,所以只会清除容器表。 这绝对应该是我刚刚错过或不理解的简单事情。我将不胜感激。
对于迁移,我使用 Flyway 来测试 Spock。
条件不满足:
user1.getId() == 1 && user1.getRiskcustomerid() == 1 && user1.getDateCreated() != null
| | | | |
| 114 | false false
| false
BaseIntegrationTest
@ContextConfiguration
@SpringBootTest(webEnvironment = DEFINED_PORT)
@Testcontainers
@Slf4j
abstract class BaseIntegrationTest extends Specification
protected static PostgreSQLContainer postgres = new PostgreSQLContainer()
.withDatabaseName("db")
.withUsername("root")
.withPassword("root")
def setupSpec()
startPostgresIfNeeded()
['spring.datasource.url' : postgres.getJdbcUrl(),
'spring.datasource.username': postgres.getUsername(),
'spring.datasource.password': postgres.getPassword()
].each k, v ->
System.setProperty(k, v)
private static void startPostgresIfNeeded()
if (!postgres.isRunning())
log.info("[BASE-INTEGRATION-TEST] - Postgres is not started. Running...")
postgres.start()
def cleanupSpec()
if (postgres.isRunning())
log.info("[BASE-INTEGRATION-TEST] - Stopping Postgres...")
postgres.stop()
UserRepositoryIntSpec
class UserRepositoryIntSpec extends BaseIntegrationTest
@Autowired
private UserRepository UserRepository
def setup()
UserRepository.deleteAll()
def "FindAll returns all users correctly"()
given:
List<Integer> friends = [1,2]
User User1 = User.builder()
.riskcustomerid(1)
.possibleids([1000, 1001])
.preferableid(1000)
.totalfriendscount(2)
.friends(friends)
.build()
User User2 = User.builder()
.riskcustomerid(2)
.possibleids([8000, 8001])
.preferableid(8000)
.totalfriendscount(3)
.friends(friends)
.build()
when:
UserRepository.saveAll([User1, User2])
then:
List<User> Users = UserRepository.findAll()
assert Users.size() == 2
User user1 = Users.get(0)
User user2 = Users.get(1)
assert user1.getId() == 1 && user1.getRiskcustomerid() == 1 && user1.getDateCreated() != null
assert user2.getId() == 2 && user2.getRiskcustomerid() == 2 && user2.getDateCreated() != null
Application.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/db
username: root
password: root
hikari:
connection-timeout: 10000
leak-detection-threshold: 60000
validation-timeout: 30000
connection-test-query: SELECT 1;
jdbc-url: jdbc:postgresql://localhost:5432/db
username: root
password: root
data-source-properties: stringtype=unspecified
maximum-pool-size: 16
max-lifetime: 1800000
transaction-isolation: TRANSACTION_READ_COMMITTED
pool-name: hikari.local
driver-class-name: org.postgresql.Driver
jpa:
hibernate:
ddl-auto: update
flyway:
schemas: schema1
baseline-on-migrate: false
server:
port: 8080
【问题讨论】:
id和count有什么关系?此外,通过持久测试对 ID 进行断言通常是一个糟糕的想法。如果您有多个测试,则序列会增加更多。 这就是为什么我有设置块,它将在每次测试之前运行。但我也不明白为什么用户表每次都在本地数据库中变得清晰,因为我希望测试在具有新创建的数据库的容器中运行。 id 和计数还有什么关系?删除数据不会重置序列。不要假设 ID 是一个,假设有一个。虽然你不信任 uibernate 有什么用?如果我们保存了它,它就有一个 id。 好吧,让我们忘记计数。但是为什么使用本地数据库而不是容器一?为什么本地表清楚并使用,但没有容器表?我假设事实上,每次我向本地数据库添加信息时,它实际上会在测试后被删除 我会说因为setupSpec
是在应用程序启动后执行的。
【参考方案1】:
我看到您使用的是url: jdbc:postgresql://localhost:5432/db
。您实际上是在说“请针对我的本地数据库运行”:)
对于您的用例,我建议在 Testcontainers 中使用 JDBC-based containers。它将自动启动容器并在您关闭与它的最后一个连接时将其销毁。
【讨论】:
是的,到底是什么问题。谢谢!以上是关于使用 SpringBootTest 的 TestContainers 中的 DB 容器出现问题的主要内容,如果未能解决你的问题,请参考以下文章
使用@SpringBootTest时如何在测试类中自动装配bean
使用 SpringBootTest 和 Autowired 注解时 LogCaptor 无法捕获
_mm256_testc_pd、_mm256_testz_pd、_mm256_testnzc_pd 是干啥用的?
Spring Boot 2.x 实践记:@SpringBootTest