こんにちは。virapture株式会社のもぐめっとです。
最近もっぱら休みの日は山にこもって雪山に土下座する毎日なので自分の顔写真がないのが最近の悩みです。
本日はfirestoreのエミュレータを使ったunit testの方法について紹介します。
事前準備
firebaseコマンドでエミュレータを起動できるようにしておきます。
npm install -g firebase-tools
cd {firebase.jsonを定義してるところがあるのディレクトリ}
firebase.jsonがなければ下記コマンドでプロジェクトの設定をしましょう。
firebase init
emulatorを起動します。
firebase start emulator
これで準備おk!
unit testの準備
肝としては2点あります。
それが、emulatorを使うようにする設定と、testの度にデータを削除する仕組みです。
emulatorを使うようにするには下記のような書き方を行います。
val firestoreHost = "10.0.2.2"
val firestorePort = 8080
val db = Firebase.firestore.apply {
this.useEmulator(firestoreHost, firestorePort)
this.firestoreSettings = firestoreSettings {
isPersistenceEnabled = false
}
}
データの削除はどうやるかなんですが、実はemulatorにはAPIがあって、それを叩くことでデータの削除を行います。
suspend fun deleteData() = withContext(Dispatchers.IO) {
val projectName = "hoge"
val url =
URL("http://${firestoreHost}:${firestorePort}/emulator/v1/projects/${projectName}/databases/(default)/documents")
val con = (url.openConnection() as HttpURLConnection).apply {
this.requestMethod = "DELETE"
this.instanceFollowRedirects = false
this.connectTimeout = 5000
this.readTimeout = 5000
this.setRequestProperty("Content-Type", "application/json; charset=utf-8")
}
con.responseCode
con.disconnect()
}
ということでこれらをいい感じに纏めたUtilを用意しておきます。
class FirestoreTestUtil {
companion object {
private const val firestoreHost = "10.0.2.2"
private const val firestorePort = 8080
val db = Firebase.firestore.apply {
useEmulator(firestoreHost, firestorePort)
firestoreSettings = firestoreSettings {
isPersistenceEnabled = false
}
}
suspend fun deleteData() = withContext(Dispatchers.IO) {
val projectName = "hoge"
val url =
URL("http://${firestoreHost}:${firestorePort}/emulator/v1/projects/${projectName}/databases/(default)/documents")
val con = (url.openConnection() as HttpURLConnection).apply {
requestMethod = "DELETE"
instanceFollowRedirects = false
connectTimeout = 5000
readTimeout = 5000
setRequestProperty("Content-Type", "application/json; charset=utf-8")
}
con.responseCode
con.disconnect()
}
}
}
実際にエミュレータを使ったunit testを書く
先程作ったutilを使ってこんな感じで書きます。
@ExperimentalCoroutinesApi
class CustomerRepositoryTest {
private var db = FirestoreTestUtil.db
companion object {
@BeforeClass @JvmStatic
fun setup() {
runBlocking {
FirestoreTestUtil.deleteData()
}
}
}
@Before
fun before() {
val collection = db.collection("customers")
val customerData = mapOf(
"firstName" to "Test",
"lastName" to "Customer",
"createdAt" to Timestamp.now(),
"updatedAt" to Timestamp.now()
)
collection.document("testcustomer").set(customerData)
}
@After
fun tearDown() {
runBlocking {
FirestoreTestUtil.deleteData()
}
}
@Test
fun findById() = runTest {
val repository = CustomerRepository(db)
val customer = repository.findById("testcustomer")
assertNotNull(customer)
customer?.run {
assertEquals("Test", firstName)
assertEquals("Customer", lastName)
}
}
}
まとめ
androidとfirestoreでもemulatorを使ったunit testを無事書くことができるようになりました!
削除するときに癖がちょっとありますが、これでいい感じにできるはずです!
これでよいTDDライフを送れることでしょう!
最後に、ワンナイト人狼オンラインというゲームを作ってます!よかったら遊んでね!
他にもCameconやOffchaといったサービスも作ってるのでよかったら使ってね!
また、チームビルディングや技術顧問、Firebaseの設計やアドバイスといったお話も受け付けてますので御用の方は弊社までお問い合わせください。