Блокировка базы данных после выполнения теста метода спока
Я пытаюсь написать интеграционный тест в спок с библиотекой Spring Boot и testcontainers.
Я создал базовый класс IntegrationSpec для всех моих интеграционных испытаний, как показано ниже:
@TypeChecked
@CompileStatic
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = [Application.class])
@Transactional
@Rollback
@ActiveProfiles("integration")
@Testcontainers
class IntegrationSpec extends Specification {
@Autowired
protected WebApplicationContext webApplicationContext
@Autowired
ObjectMapper jsonObjectMapper
@Shared
groovy.sql.Sql sql
@Autowired
void setSqlDataSource(DataSource dataSource) {
this.sql = new Sql(dataSource)
}
MockMvc mockMvc
@Shared
PostgreSQLContainer postgreSQLContainer = container
static final String DB_USERNAME = "username"
static final String DB_PASSWORD = "password"
static final String DB_NAME = "zlecenia"
static PostgreSQLContainer container = new PostgreSQLContainer("postgres:9.6.8")
.withDatabaseName(DB_NAME)
.withUsername(DB_USERNAME)
.withPassword(DB_PASSWORD)
@Before
void setupMockMvc() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
//.apply(springSecurity())
.build()
}
def cleanupSpec() {
if (sql != null)
sql.close()
if (postgreSQLContainer.isRunning()) {
println("[BASE-INTEGRATION-TEST] - Stopping Postgres...")
postgreSQLContainer.stop()
}
}
//code omitted
}
Когда я запускаю тест с 4 методами:
class BrygadaControllerSpec extends IntegrationSpec implements BrygadaSampleData {
@Shared
Clock fixedClock = Clock.fixed(Instant.parse("2019-01-01T00:00:00.00Z"), ZoneId.systemDefault())
def setupSpec() {
//to ensure our tests depends on specified time
ValidationUtils.setClock(fixedClock)
}
def setup() {
deleteFromTable("brygada")
}
def cleanup() {
deleteFromTable("brygada")
}
И ниже пример одного из методов:
def "should add new brigade"() {
given: "brigade which we want to add"
String dataOd = "01-01-2019", dataDo = "01-02-2019"
BrygadaDto brygadaDtoRequest = createBrygadaDtoForInsert(Fields.BRYGADA_1_NAME, dataOd, dataDo)
when: "I go to /brygada (POST)"
def brygadaResultDto = performPostAndMapResponseToDto("/brygada", brygadaDtoRequest, BrygadaResultDto.class)
def grantedIdByDB = brygadaResultDto.id
then: "status is ok"
brygadaResultDto.responseStatus == ResponseStatus.OK
and: 'body contains proper values'
with(brygadaResultDto) {
it.data.id != null
it.data.nazwa == Fields.BRYGADA_1_NAME
it.data.dataOd == toDate(dataOd)
it.data.dataDo == toDate(dataDo)
}
when: "I go to /brygada/$brygadaResultDto.id (GET)"
brygadaResultDto = performGetAndMapResponseToDto("/brygada/$brygadaResultDto.id", BrygadaResultDto.class)
then: "status is ok"
brygadaResultDto.responseStatus == ResponseStatus.OK
and: "body contains proper value"
with(brygadaResultDto) {
it.data.id == grantedIdByDB
it.data.nazwa == Fields.BRYGADA_1_NAME
it.data.dataOd == toDate(dataOd)
it.data.dataDo == toDate(dataDo)
}
}
И второй способ:
def "should update existing brigade"() {
given: "brigade which we want to update exists"
sql.execute("insert into brygada(id, nazwa, data_od, data_do) values (1, 'Brygada 3', '2019-01-01 00:00', '2019-12-31 00:00')")
and: "we has defined what we are going to update"
String nazwa = Fields.BRYGADA_1_NAME, dataOd = "01-01-2019", dataDo = "01-02-2019"
BrygadaDto brygadaDtoRequest = createBrygadaDtoForUpdate(Fields.BRYGADA_1_ID, nazwa, dataOd, dataDo)
when: "I go to /brygada/$Fields.BRYGADA_1_ID (PUT)"
def brygadaResultDto = performPutAndMapResponseToDto("/brygada/$Fields.BRYGADA_1_ID", brygadaDtoRequest, BrygadaResultDto.class)
then: "status is ok"
brygadaResultDto.responseStatus == ResponseStatus.OK
and: "body contains proper value"
with(brygadaResultDto) {
it.data.id == Fields.BRYGADA_1_ID
it.data.nazwa == nazwa
it.data.dataOd == toDate(dataOd)
it.data.dataDo == toDate(dataDo)
}
when: "I go to /brygada/$brygadaResultDto.id (GET)"
brygadaResultDto = performGetAndMapResponseToDto("/brygada/$brygadaResultDto.id", BrygadaResultDto.class)
then: "status is ok"
brygadaResultDto.responseStatus == ResponseStatus.OK
and: "body contains proper value"
with(brygadaResultDto) {
it.data.id == Fields.BRYGADA_1_ID
it.data.nazwa == nazwa
it.data.dataOd == toDate(dataOd)
it.data.dataDo == toDate(dataDo)
}
}
Я вижу в журналах: 2018-12-28 10: 52: 13.410 INFO 27346 --- [main] ostctransaction.TransactionContext: начата транзакция (1) для тестового контекста [DefaultTestContext@f27ea3 testClass = BrygadaControllerSpec, testInstance = pl.com.kartgis.zlecenia. com.kartgis.zlecenia.Application, класс pl.com.kartgis.zlecenia.Application}', contextInitializerClasses = '[]', activeProfiles = '{интеграция}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true, server.port=0}', contextCustomizers = set[org.spockframework.spring.mock.SpockContextCustomizer@0, org.springframework.boot.test.autoconfigure.Proa.console, org.springframe work.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@534df152, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@2145433b, org.springfratestxtOject_jectupOjectBjectExFjects_Directory_Exject_File.dll org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@17c1bced], resourceBasePath = 'src/main/webappf.s.s или для работы, contextLo. boot.test.context. -> список [[пусто]]]]; менеджер транзакций [org.springframework.orm.jpa.JpaTransactionManager@b67b359]; откат [true] 2018-12-28 10:52:13.412 INFO 27346 --- [ main] oejshContextHandler.application: инициализация Spring TestDispatcherServlet '' 2018-12-28 10:52:13.412 INFO 27346 --- [ main] ostweb.servlet.TestDispatcherServlet: Инициализация сервлета '' 2018-12-28 10:52:13.418 INFO 27346 --- [ main] ostweb.servlet.TestDispatcherServlet: Завершить инициализацию за 6 мс Hibernate: выберите brygada0_.id в качестве id1_2_0_, bryug0 как uuid2_2_0_, brygada0_.data_do как data_do3_2_0_, brygada0_.data_od как data_od4_2_0_, brygada0_.nazwa как nazwa5_2_0_ из zlecenia.brygada brygada0_, где brygada = brygada? Спящий режим: обновление zlecenia.brygada set uuid=?, data_do =?, data_od =?, nazwa =? где id=? Гибернация: выберите brygada0_.id в качестве id1_2_, brygada0_.uuid в качестве uuid2_2_, brygada0_.data_do в качестве data_do3_2_, brygada0_.data_od в качестве data_od4_2_, brygada0_.nazwa в качестве нового юриста
Проблема заключается в том, что после выполнения первого метода тестирования в базе данных postgres возникает некоторая тупиковая ситуация, и проверка никогда не завершается. У меня есть несколько вопросов:
- Правильна ли моя тестовая конфигурация? Я имею в виду выражение контейнера (это должен быть статический var и @Shared?)
- Я использую liquibase, и я вижу, что сценарии выполняются перед первым тестовым классом - это поведение expexted? Meybe лучше, когда скрипты выполняются перед каждым тестовым классом (сбросить схему / создать и т. Д.)
- Каждое выполнение тестового метода вызывает запуск контейнера...
1 ответ
Я использую объект groovy.sql.Sql и аннотацию @Transactional, объект sql использует не одно и то же соединение.
Мы можем создать объект на соединение в текущем тестовом методе (метод транзакционный)
protected Sql getSqlObject() {
Connection connection = DataSourceUtils.getConnection(dataSource)
return new Sql(connection)
}
И теперь я могу использовать в моем методе тестирования, как показано ниже:
def "should get brigade"() {
given: "brigade exists"
getSqlObject().execute("insert into brygada(id, nazwa, data_od, data_do) values (1, 'Brygada 3', '2018-01-01 00:00', '2018-12-31 00:00')")
Я думаю, что проблема решена!