iT邦幫忙

2025 iThome 鐵人賽

DAY 5
0
Software Development

每天一點 Ktor 3.0:一個月學會 Kotlin 後端開發系列 第 5

Day 05:用 DAO 改寫 UserService 並加上自動化測試

  • 分享至 

  • xImage
  •  

首先我們改寫一下資料表的格式

object Users : IntIdTable() {
    val name = varchar("name", length = 50)
    val age = integer("age")
}

使用 IntIdTable 比起之前的 Table 更加簡潔

針對單一資料物件的操作,我們要加上一個新的類別 UserEntity

class UserEntity(id: EntityID<Int>) : IntEntity(id) {
    companion object : IntEntityClass<UserEntity>(Users)
    var name by Users.name
    var age by Users.age
}

至於資料表裡面的操作,我們改寫成這樣

suspend fun create(user: ExposedUser): Int = dbQuery {
    val entity = UserEntity.new {
        name = user.name
        age = user.age
    }
    entity.id.value
}

suspend fun read(id: Int): ExposedUser? = dbQuery {
    UserEntity.findById(id)?.let { ExposedUser(it.name, it.age) }
}

suspend fun update(id: Int, user: ExposedUser) {
    dbQuery {
        UserEntity.findById(id)?.apply {
            name = user.name
            age = user.age
        }
    }
}

suspend fun delete(id: Int) {
    dbQuery {
        UserEntity.findById(id)?.delete()
    }
}

接著我們就可以照樣使用 UserService 了!使用的方式和之前沒有差異

我們可以撰寫一個自動化測試來確認 UserService 的行爲。我們加上一個新檔案 src/test/kotlin/UserServiceTest.kt

package com.example

import kotlinx.coroutines.runBlocking
import org.jetbrains.exposed.sql.Database
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull

class UserServiceTest {
    private fun newDb(): Database = Database.connect(
        url = "jdbc:h2:mem:user_service_test_${System.nanoTime()};DB_CLOSE_DELAY=-1",
        user = "root",
        driver = "org.h2.Driver",
        password = "",
    )

    @Test
    fun testCreateAndRead() = runBlocking {
        val service = UserService(newDb())
        val newUser = ExposedUser(name = "Alice", age = 30)
        val id = service.create(newUser)
        assertNotNull(id)

        val read = service.read(id)
        assertNotNull(read)
        assertEquals("Alice", read.name)
        assertEquals(30, read.age)
    }

    @Test
    fun testUpdate() = runBlocking {
        val service = UserService(newDb())
        val id = service.create(ExposedUser("Bob", 22))

        service.update(id, ExposedUser("Bobby", 23))
        val read = service.read(id)
        assertNotNull(read)
        assertEquals("Bobby", read.name)
        assertEquals(23, read.age)
    }

    @Test
    fun testDelete() = runBlocking {
        val service = UserService(newDb())
        val id = service.create(ExposedUser("Charlie", 40))

        // ensure it exists first
        assertNotNull(service.read(id))

        service.delete(id)
        val after = service.read(id)
        assertNull(after)
    }

    @Test
    fun testReadNonExistent() = runBlocking {
        val service = UserService(newDb())
        val result = service.read(999999)
        assertNull(result)
    }
}

運作測試通過之後,我們就可以更加確保我們的 UserService 沒有問題了!

今天的部分就到這邊,我們明天見!


上一篇
Day 04:Exposed DSL 的資料庫操作以及 CRUD API
下一篇
Day 06:改用 R2DBC 存取資料庫
系列文
每天一點 Ktor 3.0:一個月學會 Kotlin 後端開發6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言