2

我想知道如何在KMM上为SQLDelight编写单元测试。首先,我什至无法正确添加SQLDelight依赖项。

    val commonTest by getting {
        dependencies {
            implementation(kotlin("test-common"))
            implementation(kotlin("test-annotations-common"))
            // SQLDelight tests
            implementation("com.squareup.sqldelight:sqlite-driver:1.4.3")
        }
    }

在我添加依赖项然后同步项目后,项目甚至没有构建。有人可以告诉我这是否是添加 sqlite 驱动程序依赖项的正确方法吗?

任何帮助将不胜感激!

4

4 回答 4

5

您可以在KaMPKit中看到一个基本示例。

如果您在非测试代码中配置了 sqldelight,则不需要在commonTest.

在我们的测试代码中,我们有一个expect创建用于测试的数据库连接。

internal expect fun testDbConnection(): SqlDriver

然后在iOSAndroid代码中,actual定义。

依赖配置看起来(大致)像这样:

commonMain {
  implementation("com.squareup.sqldelight:runtime:1.4.4")
}

androidMain {
 implementation("com.squareup.sqldelight:android-driver:1.4.4")
}

iosMain {
  implementation("com.squareup.sqldelight:native-driver:1.4.4")
}

有了它,您应该能够编写 sqldelight 测试。

于 2021-01-11T14:28:09.250 回答
2

我在使用 Context 进行测试时遇到了问题,发现使用内存数据库更快。这还具有不需要设备进行测试的好处。

我这样做的方式:

  1. 将 JdbcSqliteDriver 添加到 androidTest 源集(“共享”下的 build.gradle)
val androidTest by getting {
    dependencies {
        // ...
        implementation("com.squareup.sqldelight:sqlite-driver:1.4.4")
    }
}
  1. 添加期望/实际函数来创建驱动程序:
  • 在“commonTest”目录下的文件中(例如 createTestSqlDriver.kt)

internal expect fun createTestSqlDriver(): SqlDriver

  • 在“androidTest”下的文件中
internal actual fun createTestSqlDriver(): SqlDriver {
    return JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY).apply {
        MyDatabase.Schema.create(this)
    }
}
  1. 现在我可以在“commonTest”下的测试中创建和使用数据库。就像是:
internal class MyClassDbTests {

    private val sqlDriver = createTestSqlDriver()
    private val myDatabase = MyDatabase(sqlDriver)

    fun insert_addItems_verifyCorrectNumOfItemsInDb() {
        // GIVEN
        val myQueries = myDatabase.mydbQueries
        myQueries.deleteAllEvents()
        
        val numItemsBeforeInsertion = myQueries.selectAll().executeAsList().size

        // WHEN
        myQueries.insertItem(1, 2, 3)
        myQueries.insertItem(10, 20, 30)

        val numItemsAfterInsertion = myQueries.selectAll().executeAsList().size

        // THEN
        assertEquals(0, numItemsBeforeInsertion)
        assertEquals(2, numItemsAfterInsertion)
    }
}

我发现以下帖子很有用:

于 2021-06-08T04:23:37.257 回答
0

例子

package com.viki.vikilitics_kmm

import com.squareup.sqldelight.sqlite.driver.JdbcDriver
import com.google.common.truth.Truth.assertThat
import com.squareup.sqldelight.db.SqlDriver
import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver
import com.viki.vikiliticskmm.Event
import com.viki.vikiliticskmm.EventQueries
import org.junit.After
import org.junit.Before
import org.junit.Test
import java.sql.DriverManager
import java.sql.Connection


class AndroidEventDatabaseTest {
    private lateinit var queries: EventQueries

    // When your test needs a driver
    @Before
    fun before() {
        val driver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)

        val database = EventDatabase(driver)

        EventDatabase.Schema.create(driver)
        queries = database.eventQueries
    }


    @Test
    fun `select all events`() {
        queries.insertEvent("1", "2", "{Click,Open}")
        queries.insertEvent("2", "2", "{Click,Close}")

        assertThat(queries.selectAllEvents().executeAsList())
            .containsExactly(
                Event(
                    as_counter = "1",
                    t_ms = "2",
                    event_map = "{Click,Open}"
                ),
                Event(
                    as_counter = "2",
                    t_ms = "2",
                    event_map = "{Click,Close}"
                )
            )
    }

    @Test
    fun `delete multiple events`() {

        queries.insertEvent("1", "1", "{Click,Open}")
        queries.insertEvent("1", "2", "{Click,Close},{Read,Open}")
        queries.insertEvent("1", "3", "{Click,Open}")
        queries.insertEvent("2", "3", "{Click,Open}")

        val event1 = listOf("1","3")
        val event2 = listOf("1","2")
        val event3 = listOf("1","4")
        val eventList = listOf(event1,event2,event3)
        for (event in eventList){
            queries.deleteEventListByKey(event.elementAt(0), event.elementAt(1))
        }

        assertThat(queries.selectAllEvents().executeAsList())
            .containsExactly(
                Event(
                    as_counter = "1",
                    t_ms = "1",
                    event_map = "{Click,Open}"
                ), Event(
                    as_counter = "2",
                    t_ms = "3",
                    event_map = "{Click,Open}"
                ),
            )

    }

    @Test
    fun `delete single event`() {

        queries.insertEvent("1", "1", "{Click,Open}")
        queries.insertEvent("1", "2", "{Click,Close},{Read,Open}")
        queries.insertEvent("1", "3", "{Click,Open}")
        queries.insertEvent("2", "3", "{Click,Open}")
        queries.deleteEventListByKey("1", "3")

        assertThat(queries.selectAllEvents().executeAsList())
            .containsExactly(
                Event(
                    as_counter = "1",
                    t_ms = "1",
                    event_map = "{Click,Open}"
                ), Event(
                    as_counter = "2",
                    t_ms = "3",
                    event_map = "{Click,Open}"
                ),
                Event(
                    as_counter = "1",
                    t_ms = "2",
                    event_map = "{Click,Close},{Read,Open}"
                )
            )

    }

    @Test
    fun `update events`() {

        queries.insertEvent("1", "2", "{Click,Open}")
        queries.insertEvent("1", "2", "{Click,Close}")
        assertThat(queries.selectAllEvents().executeAsList())
            .containsExactly(
                Event(
                    as_counter = "1",
                    t_ms = "2",
                    event_map = "{Click,Close}"
                )
            )


    }

}

参考 https://github.com/touchlab/KaMPKit/blob/main/shared/src/commonTest/kotlin/co/touchlab/kampkit/SqlDelightTest.kt

于 2021-06-17T02:31:37.107 回答
0

感谢你的回答!我遇到了另一个问题。“预期的函数‘createDriver’在 JVM 的模块 KMM.shared (test) 中没有实际声明”。在 KaMPKit 项目中,我没有找到任何与 JVM 相关的内容。

使用 SQLite 在 JVM 上入门包含必要的说明。

您需要添加一个依赖项

dependencies {
  implementation "com.squareup.sqldelight:sqlite-driver:1.5.0"
}

进入你的“jvmMain”sourceSet,接下来在你的“jvmMain”模块中实现真正有趣的createDriver。


我很欣赏 Kevin 的回答,并补充说使用 SqlDeLite 的测试应该放在平台模块(“androidTest”和“iosTest”)中,而不是“commonTest”中。

您需要向您的 SUT 提供实际驱动程序的实现,使用应用程序上下文。对于单元测试,您需要替代上下文,例如查看Robolectric

添加依赖项

dependencies {
    implementation("org.robolectric:robolectric:4.4")
}

进入“androidTest”sourceSet(我不知道什么可以用于iOS),获取应用程序上下文:

val context = ApplicationProvider.getApplicationContext<Context>()

并使用它来获取驱动程序的平台实现:

val driver = DatabaseDriverFactory(context).createDriver(Database.Schema, "test.db")
于 2021-05-18T15:41:05.393 回答