Skip to content

Commit

Permalink
Merge pull request #6 from f-lab-edu/feature/5
Browse files Browse the repository at this point in the history
[#5] 지역코드/시군구코드 로컬 저장
  • Loading branch information
ksw4015 authored Oct 7, 2024
2 parents 4ea285a + 9c6cae1 commit 1cea513
Show file tree
Hide file tree
Showing 16 changed files with 408 additions and 8 deletions.
19 changes: 13 additions & 6 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ android {
versionCode = 1
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunner = "kr.ksw.visitkorea.HiltTestRunner"
vectorDrawables {
useSupportLibrary = true
}
Expand Down Expand Up @@ -74,11 +74,6 @@ dependencies {
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)

// hilt
implementation(libs.hilt.android)
ksp(libs.hilt.compiler)
ksp(libs.androidx.hilt.compiler)

// room
implementation(libs.androidx.room.ktx)
ksp(libs.androidx.room.compiler)
Expand All @@ -88,6 +83,17 @@ dependencies {
implementation(libs.retrofit.converter.gson)
implementation(libs.okhttp)

// hilt
implementation(libs.hilt.android)
ksp(libs.hilt.compiler)
ksp(libs.androidx.hilt.compiler)
androidTestImplementation(libs.androidx.core.testing)

// workmanager
implementation(libs.androidx.hilt.work)
implementation(libs.androidx.work)

// test
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
Expand All @@ -100,4 +106,5 @@ dependencies {

androidTestImplementation(libs.hilt.android.testing)
kspAndroidTest(libs.hilt.compiler)
kspAndroidTest(libs.androidx.hilt.compiler)
}
16 changes: 16 additions & 0 deletions app/src/androidTest/java/kr/ksw/visitkorea/HiltTestRunner.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package kr.ksw.visitkorea

import android.app.Application
import android.content.Context
import androidx.test.runner.AndroidJUnitRunner
import dagger.hilt.android.testing.HiltTestApplication

class HiltTestRunner: AndroidJUnitRunner() {
override fun newApplication(
cl: ClassLoader?,
className: String?,
context: Context?
): Application {
return super.newApplication(cl, HiltTestApplication::class.java.name, context)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package kr.ksw.visitkorea.data.local.dao

import androidx.test.filters.SmallTest
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import kotlinx.coroutines.test.runTest
import kr.ksw.visitkorea.data.local.databases.AreaCodeDatabase
import kr.ksw.visitkorea.data.local.entity.AreaCodeEntity
import kr.ksw.visitkorea.data.local.entity.SigunguCodeEntity
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import javax.inject.Inject

@HiltAndroidTest
@SmallTest
class AreaCodeDaoTest {

@get:Rule
val hiltRule = HiltAndroidRule(this)

@Inject
lateinit var areaCodeDatabase: AreaCodeDatabase

private lateinit var dao: AreaCodeDao

@Before
fun setUp() {
hiltRule.inject()
dao = areaCodeDatabase.areaCodeDao
}

@After
fun tearDown() {
areaCodeDatabase.close()
}

@Test
fun getAllAreaCodeEntities_areaCodeListIsEmpty() = runTest {
assert(dao.getAllAreaCodeEntities().isEmpty())
}

@Test
fun upsertAreaCodeEntity_areaCodeIsUpserted() = runTest {
val areaCodeEntity = AreaCodeEntity(
code = "1", name = "서울"
)
dao.upsertAreaCodeEntity(areaCodeEntity)
assert(dao.getAllAreaCodeEntities().isNotEmpty())
}

@Test
fun upsertSigunguCodeEntity_sigunguCodeIsUpserted() = runTest {
val sigunguCodeEntity = SigunguCodeEntity(
areaCode = "1", code = "1", name = "강남구"
)
dao.upsertSigunguCodeEntity(sigunguCodeEntity)
assert(dao.getSigunguCodeByAreaCode("1").isNotEmpty())
}

@Test
fun `getSigunguCodeByAreaCode_sigunguCodeListByAreaCode1`() = runTest {
for(i in 1..4) {
dao.upsertSigunguCodeEntity(SigunguCodeEntity(
id = i,
areaCode = "1",
code = "$i",
name = "시군구 $i"
))
}
dao.upsertSigunguCodeEntity(SigunguCodeEntity(
id = 5,
areaCode = "2",
code = "1",
name = "가평군"
))

val sigunguCodeEntities = dao.getSigunguCodeByAreaCode("1")
assert(sigunguCodeEntities.isNotEmpty())
assert(sigunguCodeEntities.size == 4)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package kr.ksw.visitkorea.data.repository

import kr.ksw.visitkorea.data.mapper.toItems
import kr.ksw.visitkorea.data.remote.dto.AreaCodeDTO
import kr.ksw.visitkorea.data.remote.model.ApiResponse
import kr.ksw.visitkorea.data.remote.model.CommonBody
import kr.ksw.visitkorea.data.remote.model.CommonHeader
import kr.ksw.visitkorea.data.remote.model.CommonItem
import kr.ksw.visitkorea.data.remote.model.CommonResponse

class FakeAndroidAreaCodeRepository : AreaCodeRepository {
private var areaCodeResponse = ApiResponse(
CommonResponse(
CommonHeader("0000", "OK"),
CommonBody(
10,
1,
17,
CommonItem(listOf(
AreaCodeDTO("1","서울"),
AreaCodeDTO("2","인천"),
AreaCodeDTO("3","대전"),
AreaCodeDTO("4","대구"),
AreaCodeDTO("5","광주"),
AreaCodeDTO("6","부산"),
AreaCodeDTO("7","울산"),
AreaCodeDTO("8","세종특별자치시"),
AreaCodeDTO("31","경기도"),
AreaCodeDTO("32","강원특별자치도")
))
)
)
)

private var sigunguCodeResponse1 = ApiResponse(
CommonResponse(
CommonHeader("0000", "OK"),
CommonBody(
5,
1,
25,
CommonItem(listOf(
AreaCodeDTO("1","강남구"),
AreaCodeDTO("2","강동구"),
AreaCodeDTO("3","강북구"),
AreaCodeDTO("4","강서구"),
AreaCodeDTO("5","관악구")
))
)
)
)
private var sigunguCodeResponse2 = ApiResponse(
CommonResponse(
CommonHeader("0000", "OK"),
CommonBody(
5,
1,
31,
CommonItem(listOf(
AreaCodeDTO("1","가평군"),
AreaCodeDTO("2","고양시"),
AreaCodeDTO("3","과천시"),
AreaCodeDTO("4","광명시"),
AreaCodeDTO("5","광주시")
))
)
)
)

private var sigunguRequest = mapOf(
"1" to sigunguCodeResponse1,
"31" to sigunguCodeResponse2
)

override suspend fun getAreaCode(): Result<List<AreaCodeDTO>> = runCatching {
areaCodeResponse.toItems()
}

override suspend fun getSigunguCode(areaCode: String): Result<List<AreaCodeDTO>> = runCatching {
sigunguRequest[areaCode]!!.toItems()
}
}
38 changes: 38 additions & 0 deletions app/src/androidTest/java/kr/ksw/visitkorea/di/TestAppModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package kr.ksw.visitkorea.di

import android.app.Application
import androidx.room.Room
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dagger.hilt.testing.TestInstallIn
import kr.ksw.visitkorea.data.di.DataModule
import kr.ksw.visitkorea.data.local.databases.AreaCodeDatabase
import kr.ksw.visitkorea.data.repository.AreaCodeRepository
import kr.ksw.visitkorea.data.repository.FakeAndroidAreaCodeRepository
import javax.inject.Singleton

@Module
@TestInstallIn(
components = [SingletonComponent::class],
replaces = [DataModule::class]
)
object TestAppModule {

@Provides
@Singleton
fun provideAreaCodeDatabase(application: Application): AreaCodeDatabase {
return Room.inMemoryDatabaseBuilder(
application,
AreaCodeDatabase::class.java
).build()
}

@Provides
@Singleton
fun provideAreaCodeRepository(): AreaCodeRepository {
return FakeAndroidAreaCodeRepository()
}

}
12 changes: 12 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.VisitKorea">

<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="{applicationId}.androidx-startup"
android:exported="false"
tools:replace="android:authorities">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove"/>
</provider>

<activity
android:name=".presentation.splash.SplashActivity"
android:exported="true"
Expand Down
13 changes: 12 additions & 1 deletion app/src/main/java/kr/ksw/visitkorea/app/VisitKoreaApp.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
package kr.ksw.visitkorea.app

import android.app.Application
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import dagger.hilt.android.HiltAndroidApp
import javax.inject.Inject

@HiltAndroidApp
class VisitKoreaApp : Application()
class VisitKoreaApp : Application(), Configuration.Provider {
@Inject
lateinit var hiltWorkerFactory: HiltWorkerFactory

override val workManagerConfiguration: Configuration
get() = Configuration.Builder()
.setWorkerFactory(hiltWorkerFactory)
.build()
}
13 changes: 13 additions & 0 deletions app/src/main/java/kr/ksw/visitkorea/data/di/DataModule.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package kr.ksw.visitkorea.data.di

import android.app.Application
import androidx.room.Room
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kr.ksw.visitkorea.data.local.databases.AreaCodeDatabase
import kr.ksw.visitkorea.data.remote.api.AreaCodeApi
import kr.ksw.visitkorea.data.remote.api.RetrofitInterceptor
import kr.ksw.visitkorea.data.repository.AreaCodeRepository
Expand Down Expand Up @@ -37,6 +40,16 @@ object DataModule {
.build()
}

@Provides
@Singleton
fun provideAreaCodeDatabase(application: Application): AreaCodeDatabase {
return Room.databaseBuilder(
application,
AreaCodeDatabase::class.java,
"area_code.db"
).build()
}

@Provides
@Singleton
fun provideAreaCodeApi(retrofit: Retrofit): AreaCodeApi = retrofit.create(AreaCodeApi::class.java)
Expand Down
22 changes: 22 additions & 0 deletions app/src/main/java/kr/ksw/visitkorea/data/local/dao/AreaCodeDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package kr.ksw.visitkorea.data.local.dao

import androidx.room.Dao
import androidx.room.Query
import androidx.room.Upsert
import kr.ksw.visitkorea.data.local.entity.AreaCodeEntity
import kr.ksw.visitkorea.data.local.entity.SigunguCodeEntity

@Dao
interface AreaCodeDao {
@Upsert
suspend fun upsertAreaCodeEntity(areaCodeEntity: AreaCodeEntity)

@Upsert
suspend fun upsertSigunguCodeEntity(sigunguCodeEntity: SigunguCodeEntity)

@Query("SELECT * FROM area_code")
suspend fun getAllAreaCodeEntities(): List<AreaCodeEntity>

@Query("SELECT * FROM sigungu_code WHERE areaCode = :areaCode")
suspend fun getSigunguCodeByAreaCode(areaCode: String): List<SigunguCodeEntity>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package kr.ksw.visitkorea.data.local.databases

import androidx.room.Database
import androidx.room.RoomDatabase
import kr.ksw.visitkorea.data.local.dao.AreaCodeDao
import kr.ksw.visitkorea.data.local.entity.AreaCodeEntity
import kr.ksw.visitkorea.data.local.entity.SigunguCodeEntity

@Database(
entities = [AreaCodeEntity::class, SigunguCodeEntity::class],
version = 1
)
abstract class AreaCodeDatabase: RoomDatabase() {
abstract val areaCodeDao: AreaCodeDao
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package kr.ksw.visitkorea.data.local.entity

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity("area_code")
data class AreaCodeEntity(
@PrimaryKey(autoGenerate = true)
val id: Int? = null,
val code: String,
val name: String,
)
Loading

0 comments on commit 1cea513

Please sign in to comment.