コンテンツにスキップ

Testcontainersを使ってFirestoreのユニットテストをする

以下のようなベースクラスを継承してユニットテストを書くと便利。

open class FirestoreTestBase {
    protected lateinit var firestore: Firestore

    @BeforeEach
    open fun beforeEach() {
        firestore = FirestoreOptions.getDefaultInstance().toBuilder()
            .setEmulatorHost(CONTAINER.emulatorEndpoint)
            .setCredentials(FirestoreOptions.EmulatorCredentials())
            .setProjectId("test-project")
            .build()
            .service
    }

    @AfterEach
    open fun afterEach() {
        firestore.listCollections().forEach { collectionRef ->
            deleteCollection(collectionRef, DELETE_BATCH_SIZE)
        }
        firestore.close()
    }

    /**
     * ここに書いてあるやりかた。
     * ref: https://firebase.google.com/docs/firestore/manage-data/delete-data?hl=ja#collections
     *
     * なお、こういう方法もあるようだ。
     * https://firebase.google.com/docs/emulator-suite/connect_firestore?hl=ja
     */
    private fun deleteCollection(collection: CollectionReference, batchSize: Int) {
        try {
            // retrieve a small batch of documents to avoid out-of-memory errors
            val documents = collection.limit(batchSize).get().get().documents

            var deleted = 0
            documents.forEach { document ->
                document.reference.delete()
                ++deleted
            }

            if (deleted >= batchSize) {
                // retrieve and delete another batch
                deleteCollection(collection, batchSize)
            }
        } catch (e: Exception) {
            log.error("Error deleting collection", e)
        }
    }

    companion object {
        private val log = KotlinLogging.logger {}
        private val CONTAINER = FirestoreEmulatorContainer(
            DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:381.0.0-emulators")
        ).apply {
            start()
            log.info("Start firebase container. endpoint={}", emulatorEndpoint)
        }
        private const val DELETE_BATCH_SIZE = 1000
    }
}

なおTestcontainersの 公式ドキュメント では以下のようにしているが、

FirestoreOptions.getDefaultInstance().toBuilder()
    .setHost(CONTAINER.emulatorEndpoint)
    .setCredentials(NoCredentials.getInstance())

このようにしておかないと firestore.listCollections()等が認証不足?で呼び出せないので注意。

FirestoreOptions.getDefaultInstance().toBuilder()
    .setEmulatorHost(CONTAINER.emulatorEndpoint)
    .setCredentials(FirestoreOptions.EmulatorCredentials())

最終更新日: 2022/04/19 02:30