iT邦幫忙

2021 iThome 鐵人賽

DAY 16
1

知道什麼是自動測試之後,我們來看看怎麼進行和資料庫互動的自動測試。

測試目標

假設我們現有的資料關聯有 usertag 的多對多關聯

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"  
	)
	// 其他函數寫在後面
}

我們今天測試的程式,是一個用來寫入 usertag 的函數,我們一開始寫法是這樣

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()
			)  
		}  
	}
}

運作測試之後,如果順利的話,我們會得到綠燈。

這樣我們第一階段的測試就完成了!

重複寫入 Tag

接著,我們想到一個新的狀況:如果一個 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 覆蓋掉所有 useruser.tags

所以我們重新調整一下 userAddTag 函數

fun userAddTag(user: User, tag: Tag) {
    transaction {
     user.tags = SizedCollection(
         user.tags.toList() 
         + listOf(tag)
     )
    }
}

重新運作一次測試,我們就會發現兩個測試都通過了!


上一篇
[Day 15] println() 測試不好嗎?來談談什麼是自動測試?
下一篇
[Day 17] 新功能的測試,檢驗不應該存在的資料
系列文
Kotlin 怎麼操作資料庫?談談 Kotlin Exposed 框架30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言