知道什麼是自動測試之後,我們來看看怎麼進行和資料庫互動的自動測試。
假設我們現有的資料關聯有 user
和 tag
的多對多關聯
object Users : IntIdTable() {
val name = varchar("name", 50)
}
object Tags : IntIdTable() {
val name = varchar("name", 50)
}
object UsersTags : IntIdTable() {
val user = reference("user", Users)
val tag = reference("tag", Tags)
}
class Tag(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<Tag>(Tags)
var name by Tags.name
var users by User via UsersTags
}
class User(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<User>(Users)
var name by Users.name
var tags by Tag via UsersTags
}
並且連接 MySQL 的資料庫
fun main() {
Database.connect(
"jdbc:mysql://localhost:3306/exposedyoutubedemo?useSSL=false",
driver = "com.mysql.jdbc.Driver",
user = "user",
password = "password"
)
// 其他函數寫在後面
}
我們今天測試的程式,是一個用來寫入 user
和 tag
的函數,我們一開始寫法是這樣
fun userAddTag(user: User, tag: Tag) {
// user 多加一個新的 tag
transaction {
user.tags = SizedCollection(listOf(tag))
}
}
接著,我們來測試一下這段程式吧!
在自動測試階段,很重要的一個事項,是不能更動到正式的資料庫。畢竟我們不會希望有人不小心在正式環境運行了測試程式,就導致正式資料全部被搞亂了。
那麼,要怎麼在測試階段和正式階段所串連的資料庫不一樣呢?
利用我們 Day 14 的文章內容,我們可以將原本程式稍微調整,讓連線改成用測試環境的資料庫進行測試。
假設我們希望改成利用 H2 in memory 的資料庫進行測試,跟上次類似,我們在 tests/kotlin/
資料夾內,建立一個 UserAddTagKtTest.kt
檔案,來測試這個函數。
internal class UserAddTagKtTest {
fun `測試全新用戶加上標籤`() {
Database.connect("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;", driver = "org.h2.Driver")
transaction {
SchemaUtils.create(Users)
SchemaUtils.create(Tags)
SchemaUtils.create(UsersTags)
val testUser = User.new {
name = "TestUser"
}
val testTag = Tag.new {
name = "TestTag"
}
userAddTag(testUser, testTag)
assertEquals(
listOf(testTag),
testUser.tags.toList()
)
}
}
}
運作測試之後,如果順利的話,我們會得到綠燈。
這樣我們第一階段的測試就完成了!
接著,我們想到一個新的狀況:如果一個 user
寫入多個 tag
,那麼還會成功嗎?
我們用類似的邏輯,再寫一個測試案例
@Test
fun `測試用戶加上多個標籤`() {
Database.connect("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;", driver = "org.h2.Driver")
transaction {
SchemaUtils.create(Users)
SchemaUtils.create(Tags)
SchemaUtils.create(UsersTags)
val testUser = User.new {
name = "TestUser"
}
val testTag = Tag.new {
name = "TestTag"
}
val testTag2 = Tag.new {
name = "TestTag2"
}
userAddTag(testUser, testTag)
userAddTag(testUser, testTag2)
assertEquals(
listOf(testTag, testTag2),
testUser.tags.toList()
)
}
跟前面的邏輯是幾乎一樣的,只是我們多加了一個 testTag2
這時候如果我們運作測試,會出現類似這樣的錯誤
expected:<[Tag@530069b7, Tag@3714e9e4]> but was:<[Tag@3714e9e4]>
Expected :[Tag@530069b7, Tag@3714e9e4]
Actual :[Tag@3714e9e4]
這是為什麼呢?回到我們的程式檢查,原來我們一開始的程式寫錯了!只會拿新的 Tag
覆蓋掉所有 user
的 user.tags
。
所以我們重新調整一下 userAddTag
函數
fun userAddTag(user: User, tag: Tag) {
transaction {
user.tags = SizedCollection(
user.tags.toList()
+ listOf(tag)
)
}
}
重新運作一次測試,我們就會發現兩個測試都通過了!