2

写了一个简短的便利扩展Testcontainers

fun JdbcDatabaseContainer<*>.execute(query:DSLContext.()-> Query){
    val connection = DriverManager.getConnection(this.getJdbcUrl(),this.getUsername(),this.getPassword())
    val create = DSL.using(connection)
    create.query().execute()
}

现在想测试它。

  • Flyway 加载 30 个条目。这些应该在allDataPresent
  • canInsert插入一个不带扩展名的条目
  • canInsertWithExtension做同样的事情,但通过扩展功能
  • insertMultipleWithExtension正如其名称所暗示的那样,并插入另一个 5

除了allDataPresent测试用例(因为它是只读的)之外的所有测试用例都被注释了@Transactional

因此,我希望在测试方法之后回滚这些修改。

相反,发生的是

[ERROR] Failures: 
[ERROR]   InitDataIT.allDataPresent:70 
Expecting:
 <36>
to be equal to:
 <30>
but was not.
[ERROR]   InitDataIT.canInsert:90 
Expecting:
 <6>
to be equal to:
 <1>
but was not.
[ERROR]   InitDataIT.canInsertWithExtension:112 
Expecting:
 <6>
to be equal to:
 <1>
but was not.

每个都@Test可以自己正常工作。所以问题一定出在@Transactional.

那为什么呢?更重要的是,我如何获得回滚?

完整的测试用例(也尝试注释类,没有任何区别):

@Testcontainers
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = [InitDataIT.TestContextInitializer::class])
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
open class InitDataIT {
    companion object {
        @JvmStatic
        @Container
        private val dbContainer = MySQLContainer<Nothing>().apply {
            withDatabaseName("test")
            withUsername("root")
            withPassword("")
        }
    }
    object TestContextInitializer: ApplicationContextInitializer<ConfigurableApplicationContext> {
        override fun initialize(applicationContext: ConfigurableApplicationContext) {
            TestPropertyValues.of(
                    "spring.datasource.url=${dbContainer.jdbcUrl}",
                    "spring.datasource.username=${dbContainer.username}",
                    "spring.datasource.password=${dbContainer.password}",
                    "spring.datasource.driver-class-name=${dbContainer.driverClassName}"
            ).applyTo(applicationContext)
        }
    }

    private val create:DSLContext


    @Autowired
    constructor(create:DSLContext){
        this.create = create
    }


    @Test
    fun allDataPresent(){
        //given
        val expectedNumberOfEntries = 30

        val query = create.selectCount()
                .from(CUSTOMERS)

        //when
        val numberOfEntries = query.fetchOne{it.value1()}

        //then
        Assertions.assertThat(numberOfEntries).isEqualTo(expectedNumberOfEntries)
    }

    @Test
    @Transactional
    open fun canInsert(){
        //given
        val insertquery = create.insertInto(CUSTOMERS)
                .columns(CUSTOMERS.FIRSTNAME,CUSTOMERS.LASTNAME,CUSTOMERS.EMAIL, CUSTOMERS.STATUS)
                .values("Alice","Tester","Alice.Tester@somewhere.tt",CustomerStatus.Contacted.name)

        val expectedNumberInOffice2 = 1

        //when
        insertquery.execute()

        //then
        val numberInOffice2 = create.selectCount()
                .from(CUSTOMERS)
                .where(CUSTOMERS.EMAIL.contains("somewhere"))
                .fetchOne{it.value1()}
        assertThat(numberInOffice2).isEqualTo(expectedNumberInOffice2)

    }

    @Test
    @Transactional
    open fun canInsertWithExtension(){
        //given
        dbContainer.execute {
            insertInto(CUSTOMERS)
                    .columns(CUSTOMERS.FIRSTNAME,CUSTOMERS.LASTNAME,CUSTOMERS.EMAIL, CUSTOMERS.STATUS)
                    .values("Alice","Tester","Alice.Tester@somewhere.tt",CustomerStatus.Contacted.name)
        }

        val expectedNumberInOffice2 = 1

        //when
        val numberInOffice2 = create.selectCount()
                .from(CUSTOMERS)
                .where(CUSTOMERS.EMAIL.contains("somewhere"))
                .fetchOne{it.value1()}

        //then
        assertThat(numberInOffice2).isEqualTo(expectedNumberInOffice2)

    }

    @Test
    @Transactional
    open fun insertMultipleWithExtension(){
        //given
        dbContainer.execute {
            insertInto(CUSTOMERS)
                    .columns(CUSTOMERS.FIRSTNAME,CUSTOMERS.LASTNAME,CUSTOMERS.EMAIL, CUSTOMERS.STATUS)
                    .values("Alice","Make","Alice.Make@somewhere.tt", CustomerStatus.Customer.name)
                    .values("Bob","Another","Bob.Another@somewhere.tt", CustomerStatus.ClosedLost.name)
                    .values("Charlie","Integration","Charlie.Integration@somewhere.tt",CustomerStatus.NotContacted.name)
                    .values("Denise","Test","Denise.Test@somewhere.tt",CustomerStatus.Customer.name)
                    .values("Ellie","Now","Ellie.Now@somewhere.tt",CustomerStatus.Contacted.name)
        }

        val expectedNumberInOffice2 = 5

        //when
        val numberInOffice2 = create.selectCount()
                .from(CUSTOMERS)
                .where(CUSTOMERS.EMAIL.contains("somewhere"))
                .fetchOne{it.value1()}

        //then
        assertThat(numberInOffice2).isEqualTo(expectedNumberInOffice2)
    }

}
4

1 回答 1

2

Spring@Transactional注释不仅可以神奇地与您DriverManager创建的 JDBC 连接一起使用。您的dbContainer对象应该在您的 spring 托管数据源上运行。

于 2019-04-11T21:48:20.147 回答