Skip to content

Commit

Permalink
[경북대 Android_유지예] 5주차 과제_Step 0 (#34)
Browse files Browse the repository at this point in the history
* docs:readme.md

* feat: step0 code upload with package, mocking

---------

Co-authored-by: 유지예 <[email protected]>
  • Loading branch information
YJY1220 and 유지예 authored Jul 24, 2024
1 parent 305453d commit c9d8ff5
Show file tree
Hide file tree
Showing 42 changed files with 1,520 additions and 71 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
# android-map-refactoring
### KakaoTechCampus 2기 Step2 - 5주차 과제 : 리팩토링

### 0단계. 4주차 코드 반영하기
74 changes: 41 additions & 33 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import java.util.Properties

fun getApiKey(key: String): String {
val properties = Properties()
file("../local.properties").inputStream().use { properties.load(it) }
return properties.getProperty(key)
}

plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("org.jlleitschuh.gradle.ktlint")
id("kotlin-parcelize")
id("kotlin-kapt")
id("com.google.dagger.hilt.android")
}

android {
Expand All @@ -19,6 +23,10 @@ android {
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

//API 가져오기
resValue("string", "kakao_api_key", getApiKey("KAKAO_API_KEY"))
buildConfigField("String", "KAKAO_REST_API_KEY", "\"${getApiKey("KAKAO_REST_API_KEY")}\"")
}

buildTypes {
Expand All @@ -30,51 +38,51 @@ android {
)
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

kotlinOptions {
jvmTarget = "17"
}

buildFeatures {
viewBinding = true
dataBinding = true
buildConfig = true
}
}

dependencies {

implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("com.google.android.material:material:1.12.0")
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.recyclerview:recyclerview:1.3.2")
implementation("com.squareup.retrofit2:retrofit:2.11.0")
implementation("com.squareup.retrofit2:converter-gson:2.11.0")
implementation("androidx.datastore:datastore-preferences:1.0.0")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.9.0")
implementation("com.kakao.sdk:v2-user:2.10.0") // Kakao SDK 추가
implementation("com.kakao.maps.open:android:2.9.5")
implementation("androidx.activity:activity-ktx:1.9.0")
implementation("androidx.test:core-ktx:1.6.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.3")
implementation("androidx.room:room-runtime:2.6.1")
kapt("androidx.room:room-compiler:2.6.1")
implementation("com.google.dagger:hilt-android:2.48.1")
kapt("com.google.dagger:hilt-compiler:2.48.1")
implementation("androidx.activity:activity-ktx:1.9.0")
implementation("androidx.room:room-ktx:2.6.1")
testImplementation("androidx.room:room-testing:2.6.1")
implementation("androidx.activity:activity:1.8.0")
testImplementation("junit:junit:4.13.2")
testImplementation("io.mockk:mockk-android:1.13.11")
testImplementation("io.mockk:mockk-agent:1.13.11")
testImplementation("androidx.arch.core:core-testing:2.2.0")
testImplementation("org.robolectric:robolectric:4.11.1")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
androidTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
androidTestImplementation("androidx.test:rules:1.6.1")
androidTestImplementation("androidx.test.espresso:espresso-intents:3.6.1")
androidTestImplementation("com.google.dagger:hilt-android-testing:2.48.1")
kaptAndroidTest("com.google.dagger:hilt-android-compiler:2.48.1")
}
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
implementation("androidx.fragment:fragment-ktx:1.3.6")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.3.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1")
implementation("com.google.android.gms:play-services-maps:19.0.0")
implementation("com.google.android.material:material:1.11.0")
testImplementation ("junit:junit:4.13.2")
androidTestImplementation ("androidx.test.ext:junit:1.1.3")
androidTestImplementation ("androidx.test.espresso:espresso-core:3.4.0")
androidTestImplementation ("androidx.test:core-ktx:1.4.0")
androidTestImplementation ("androidx.test:runner:1.4.0")
androidTestImplementation ("androidx.test:rules:1.4.0")
androidTestImplementation ("org.mockito:mockito-core:3.11.2")
androidTestImplementation ("org.mockito:mockito-android:3.11.2")
androidTestImplementation ("androidx.arch.core:core-testing:2.1.0")
}
47 changes: 47 additions & 0 deletions app/src/androidTest/java/campus/tech/kakao/map/ErrorScreenTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package campus.tech.kakao.map

import android.content.Context
import android.view.View
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import campus.tech.kakao.map.ui.MainActivity
import org.junit.*
import org.junit.runner.RunWith
import org.junit.Assert.assertTrue

@RunWith(AndroidJUnit4::class)
class ErrorScreenTest {

private lateinit var scenario: ActivityScenario<MainActivity>
private lateinit var context: Context

@Before
fun setUp() {
context = InstrumentationRegistry.getInstrumentation().targetContext
scenario = ActivityScenario.launch(MainActivity::class.java)
}

@After
fun tearDown() {
if (::scenario.isInitialized) {
scenario.close()
}
}

@Test
fun testShowErrorScreen() {
scenario.onActivity { activity ->
// 에러 화면이 표시될 때까지 대기
Thread.sleep(2000)

val errorLayout: RelativeLayout = activity.findViewById(R.id.error_layout)
val errorDetails: TextView = activity.findViewById(R.id.error_details)

assertTrue(errorLayout.visibility == View.VISIBLE)
assertTrue(errorDetails.text.toString().contains("Unauthorized"))
}
}
}
178 changes: 178 additions & 0 deletions app/src/androidTest/java/campus/tech/kakao/map/FunctionTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import android.app.Activity
import android.app.Application
import android.content.Context
import android.content.Intent
import android.view.View
import android.widget.EditText
import android.widget.FrameLayout
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import campus.tech.kakao.map.model.MapItem
import campus.tech.kakao.map.repository.MapRepository
import campus.tech.kakao.map.viewmodel.MapViewModel
import campus.tech.kakao.map.viewmodel.MapViewModelFactory
import campus.tech.kakao.map.R
import campus.tech.kakao.map.ui.MainActivity
import campus.tech.kakao.map.ui.SearchActivity
import junit.framework.TestCase.assertEquals
import kotlinx.coroutines.runBlocking
import org.junit.*
import org.junit.runner.RunWith
import org.mockito.Mockito.*
import java.util.concurrent.Executors

@RunWith(AndroidJUnit4::class)
class FunctionTest {

private lateinit var scenarioMain: ActivityScenario<MainActivity>
private lateinit var scenarioSearch: ActivityScenario<SearchActivity>
private lateinit var context: Context
private lateinit var repository: MapRepository

@Before
fun setUp() {
context = InstrumentationRegistry.getInstrumentation().targetContext
repository = mock(MapRepository::class.java)

val application = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as Application
val viewModelFactory = MapViewModelFactory(application, repository)

scenarioMain = ActivityScenario.launch(MainActivity::class.java)
scenarioMain.onActivity { activity ->
activity.viewModelFactory = viewModelFactory
}
}

@After
fun tearDown() {
scenarioMain.close()
if (::scenarioSearch.isInitialized) {
scenarioSearch.close()
}
}

@Test
fun testCompleteFlow() {
scenarioMain.onActivity { mainActivity ->

val searchEditText: EditText = mainActivity.findViewById(R.id.search_edit_text)
searchEditText.performClick()

Executors.newSingleThreadExecutor().execute {
scenarioSearch = ActivityScenario.launch(SearchActivity::class.java)
scenarioSearch.onActivity { searchActivity ->

// Repository Mocking 설정
runBlocking {
`when`(repository.searchItems("바다 정원")).thenReturn(
listOf(
MapItem(
"1",
"바다 정원",
"강원도 고성군",
"카페",
127.0,
37.0
)
)
)
}

// ViewModel에 Mock Repository 주입
searchActivity.viewModel = MapViewModel(searchActivity.application, repository)

//1 검색 기능 테스트
val searchEditText: EditText = searchActivity.findViewById(R.id.searchEditText)
searchEditText.setText("바다 정원")
searchActivity.performSearch("바다 정원")

//2 recyclerview로 검색결과 보이는지 테스트
val searchResultsRecyclerView: RecyclerView =
searchActivity.findViewById(R.id.searchResultsRecyclerView)
searchResultsRecyclerView.adapter?.notifyDataSetChanged()
assertEquals(1, searchResultsRecyclerView.adapter?.itemCount)

//3. 해당 검색결과 중 하나 눌러서 지도 마커표시, bottomsheet 정보 표시
searchResultsRecyclerView.findViewHolderForAdapterPosition(0)?.itemView?.performClick()

searchActivity.setResultAndFinish(
MapItem(
"0",
"바다 정원",
"강원도 고성군",
"카페",
127.0,
37.0
)
)
val resultIntent = Intent().apply {
putExtra("place_name", "바다 정원")
putExtra("road_address_name", "강원도 고성군")
putExtra("x", 127.0)
putExtra("y", 37.0)
}

mainActivity.onActivityResult(
MainActivity.SEARCH_REQUEST_CODE,
Activity.RESULT_OK,
resultIntent
)
val bottomSheetTitle: TextView =
mainActivity.findViewById(R.id.bottomSheetTitle)
val bottomSheetAddress: TextView =
mainActivity.findViewById(R.id.bottomSheetAddress)
assertEquals("바다 정원", bottomSheetTitle.text.toString())
assertEquals("강원도 고성군", bottomSheetAddress.text.toString())

// 4. 마지막 위치 저장해서 다시 앱 실행시 해당 위치로 지도 뜨도록 하기
mainActivity.saveLastMarkerPosition(37.0, 127.0, "바다 정원", "강원도 고성군")
}

scenarioMain.recreate()
val onActivity = scenarioMain.onActivity { activity ->
activity.loadLastMarkerPosition()

val bottomSheetTitle: TextView = activity.findViewById(R.id.bottomSheetTitle)
val bottomSheetAddress: TextView =
activity.findViewById(R.id.bottomSheetAddress)
assertEquals("바다 정원", bottomSheetTitle.text.toString())
assertEquals("강원도 고성군", bottomSheetAddress.text.toString())
assertEquals(
View.VISIBLE,
activity.findViewById<FrameLayout>(R.id.bottomSheetLayout).visibility
)

// 5. searchactivity에서 저장된 검색어 남아있는지 확인하고 해당 검색어 누르면 해당 검색어로 재검색되는지 확인하기
val searchEditText: EditText = activity.findViewById(R.id.search_edit_text)
searchEditText.performClick()

Executors.newSingleThreadExecutor().execute {
scenarioSearch = ActivityScenario.launch(SearchActivity::class.java)
scenarioSearch.onActivity { searchActivity ->

val selectedItemsRecyclerView: RecyclerView =
searchActivity.findViewById(R.id.selectedItemsRecyclerView)
assertEquals(1, selectedItemsRecyclerView.adapter?.itemCount)
val selectedViewHolder =
selectedItemsRecyclerView.findViewHolderForAdapterPosition(0)
assertEquals(
"바다 정원",
selectedViewHolder?.itemView?.findViewById<TextView>(R.id.selectedItemName)?.text.toString()
)

selectedViewHolder?.itemView?.performClick()
searchActivity.performSearch("바다 정원")

val searchResultsRecyclerView: RecyclerView =
searchActivity.findViewById(R.id.searchResultsRecyclerView)
assertEquals(1, searchResultsRecyclerView.adapter?.itemCount)
}
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.example.map

import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4

import org.junit.Test
import org.junit.runner.RunWith

import org.junit.Assert.*

/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.map", appContext.packageName)
}
}
Loading

0 comments on commit c9d8ff5

Please sign in to comment.