Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

전남대 Android_오진우 6주차 과제_Step1 #66

Open
wants to merge 7 commits into
base: fivejinw
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
.DS_Store
### Android template
# Gradle files
.gradle/
build/
Expand Down Expand Up @@ -33,5 +31,6 @@ google-services.json

# Android Profiling
*.hprof
/keyStore
/app/release

# Mac OS
.DS_Store
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
# android-map-notification
## step1 구현할 기능 목록

- [ ] serviceState 값이 ON_SERVICE인 경우 지도화면으로 넘어가는 기능
- [ ] serviceState 값이 ON_SERVICE가 아닌 경우 serviceMessage 값을 띄우는 기능
- [ ] 처음 앱을 접속할 때 초기 진입 화면을 띄우는 기능
30 changes: 23 additions & 7 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,25 +1,34 @@
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties


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")
id("kotlin-parcelize")
id("com.google.gms.google-services")
}

android {
namespace = "campus.tech.kakao.map"
compileSdk = 34


defaultConfig {
applicationId = "campus.tech.kakao.map"
minSdk = 26
targetSdk = 34
versionCode = 1
versionName = "1.0"


testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
buildConfigField("String", "KAKAO_LOCAL_API_KEY", gradleLocalProperties(rootDir, providers).getProperty("KAKAO_LOCAL_API_KEY"))
buildConfigField("String", "KAKAO_BASE_URL", gradleLocalProperties(rootDir, providers).getProperty("KAKAO_BASE_URL"))
buildConfigField("String", "KAKAO_NATIVE_APP_KEY", gradleLocalProperties(rootDir, providers).getProperty("KAKAO_NATIVE_APP_KEY"))

}

buildTypes {
Expand All @@ -41,12 +50,13 @@ android {

buildFeatures {
dataBinding = true
viewBinding = 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")
Expand All @@ -55,31 +65,37 @@ dependencies {
implementation("com.squareup.retrofit2:retrofit:2.11.0")
implementation("com.squareup.retrofit2:converter-gson:2.11.0")
implementation("com.kakao.maps.open:android:2.9.5")
implementation("androidx.activity:activity-ktx:1.9.0")
implementation("androidx.activity:activity-ktx:1.9.1")
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")
implementation("androidx.activity:activity:1.8.0")
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.datastore:datastore-preferences:1.1.1")
implementation(platform("com.google.firebase:firebase-bom:33.1.2"))
implementation("com.google.firebase:firebase-analytics-ktx")
implementation("com.google.firebase:firebase-config-ktx:22.0.0")
implementation("com.google.firebase:firebase-messaging-ktx:24.0.0")
testImplementation("androidx.room:room-testing:2.6.1")
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")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.1")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation("androidx.test:rules:1.5.0")
androidTestImplementation("androidx.test.espresso:espresso-intents:3.5.1")
androidTestImplementation("androidx.test.espresso:espresso-contrib:3.5.1")
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")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package campus.tech.kakao.map.view

import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.idling.CountingIdlingResource
import androidx.test.espresso.intent.Intents.intended
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
import androidx.test.espresso.matcher.ViewMatchers.Visibility
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.intent.Intents

import org.junit.Test
import campus.tech.kakao.map.R
import org.junit.After
import org.junit.Before
import org.junit.Rule


class MapActivityTest{


@get:Rule
val activityRule = ActivityScenarioRule(MapActivity::class.java)


@Before
fun setUp() {
Intents.init()
testInit()
}

@After
fun tearDown() {
Intents.release()
}
@Test
// 초기 화면이 잘 구성되는지
fun testInit() {
onView(withId(R.id.input_search_field)).check(
matches(isDisplayed()))
onView(withId(R.id.search_icon)).check(
matches(isDisplayed()))
onView(withId(R.id.error_text)).check(
matches(withEffectiveVisibility(Visibility.GONE)))
onView(withId(R.id.map_view)).check(
matches(isDisplayed()))
}

@Test
// 오류가 났을 때 오류화면이 잘 띄워지는지
fun testError(){
activityRule.scenario.onActivity { activity ->
activity.showErrorMessageView("인증 과정 중 원인을 알 수 없는 에러가 발생했습니다")
}
onView(withId(R.id.error_text)).check(matches(isDisplayed()))
}

@Test
// 액티비티가 잘 이동하는지
fun testMoveSearchActivity(){
onView(withId(R.id.input_search_field)).perform(click())
intended(hasComponent("campus.tech.kakao.map.view.SearchActivity"))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package campus.tech.kakao.map.view


import android.app.Activity
import android.app.Instrumentation
import android.content.Intent
import android.view.View
import android.widget.EditText
import androidx.recyclerview.widget.RecyclerView
import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.Espresso.*
import androidx.test.espresso.UiController
import androidx.test.espresso.ViewAction
import androidx.test.espresso.action.ViewActions.*
import androidx.test.espresso.assertion.ViewAssertions.*
import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition
import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.Intents.*
import androidx.test.espresso.intent.matcher.IntentMatchers.*
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.rules.ActivityScenarioRule
import campus.tech.kakao.map.R
import campus.tech.kakao.map.utilities.Constants
import campus.tech.kakao.map.data.Place
import campus.tech.kakao.map.data.SavedPlace
import org.junit.After
import org.junit.Assert.*
import org.junit.Before
import org.junit.Rule
import org.junit.Test


class SearchActivityTest {

@get:Rule
var activityRule = ActivityScenarioRule(SearchActivity::class.java)

@Before
fun setUp() {
Intents.init()
}

@After
fun tearDown() {
Intents.release()
}

@Test
// 초기 화면이 잘 구성되는지
fun testInit() {
onView(withId(R.id.search_result_recyclerView)).check(
matches(isDisplayed())
)
onView(withId(R.id.input_search_field)).check(
matches(isDisplayed())
)
onView(withId(R.id.no_search_result)).check(
matches(isDisplayed())
)
onView(withId(R.id.saved_search_recyclerView)).check(
matches(isDisplayed())
)
}

@Test
// PlaceRecyclerView가 검색어를 입력했을 때 최대 15개의 데이터를 불러오는 지 확인
fun testPlaceRecyclerView() {

onView(withId(R.id.input_search_field)).check(matches(isDisplayed()))
onView(withId(R.id.search_result_recyclerView)).check(matches(isDisplayed()))
onView(withId(R.id.input_search_field)).perform(replaceText("전남대"))
Thread.sleep(1000)

activityRule.scenario.onActivity { activity ->
val inputSearchField = activity.findViewById<EditText>(R.id.input_search_field)
val placeRecyclerView =
activity.findViewById<RecyclerView>(R.id.search_result_recyclerView)
val itemCount = placeRecyclerView.adapter?.getItemCount() ?: 0
assert(itemCount in 1..15)
}
}

@Test
// recyclerview의 아이템을 클릭했을 때 이동이 잘 되는지
fun testMoveToMapActivity() {
onView(withId(R.id.input_search_field)).check(matches(isDisplayed()))
onView(withId(R.id.search_result_recyclerView)).check(matches(isDisplayed()))
onView(withId(R.id.input_search_field)).perform(replaceText("전남대"))
Thread.sleep(1000)
lateinit var place: Place

activityRule.scenario.onActivity { activity ->
val searchRecyclerView =
activity.findViewById<RecyclerView>(R.id.search_result_recyclerView)
val adapter = searchRecyclerView.adapter as PlaceViewAdapter
place = (adapter.getPlaceAtPosition(0))
}

val intent = Intent()
intent.putExtra(Constants.Keys.KEY_PLACE, place)
val result = Instrumentation.ActivityResult(Activity.RESULT_OK, intent)
onView(withId(R.id.search_result_recyclerView)).perform(
actionOnItemAtPosition<PlaceViewHolder>(
0,
click()
)
)

intending(toPackage("campus.tech.kakao.map.view.MapActivity")).respondWith(result)
}

@Test
// 아이템 클릭시 데이터가 저장되는지
fun testSavePlace() {
onView(withId(R.id.input_search_field)).check(matches(isDisplayed()))
onView(withId(R.id.search_result_recyclerView)).check(matches(isDisplayed()))
onView(withId(R.id.input_search_field)).perform(replaceText("전남대"))
Thread.sleep(1000)

var existTaget: Boolean
lateinit var place: Place
activityRule.scenario.onActivity { activity ->
val searchRecyclerView =
activity.findViewById<RecyclerView>(R.id.search_result_recyclerView)
val placeViewAdapter = searchRecyclerView.adapter as PlaceViewAdapter
place = (placeViewAdapter.getPlaceAtPosition(0))
}

onView(withId(R.id.search_result_recyclerView)).perform(
actionOnItemAtPosition<PlaceViewHolder>(0,click())
)

val newScenario = ActivityScenario.launch(SearchActivity::class.java)

newScenario.onActivity { activity ->
val savedPlaceRecyclerView =
activity.findViewById<RecyclerView>(R.id.saved_search_recyclerView)
val savedPlaceAdapter = savedPlaceRecyclerView.adapter as SavedPlaceViewAdapter
existTaget = savedPlaceAdapter.existPlace(SavedPlace(place.name))
assertTrue(existTaget)
}
}

@Test
// 삭제 버튼 클릭시 저장된 데이터가 삭제되는지
fun testRemoveSavedPlace() {
onView(withId(R.id.input_search_field)).check(matches(isDisplayed()))
onView(withId(R.id.search_result_recyclerView)).check(matches(isDisplayed()))
Thread.sleep(1000)

var existTaget: Boolean
lateinit var savedPlace: SavedPlace
lateinit var savedPlaceRecyclerView : RecyclerView
lateinit var savedPlaceAdapter : SavedPlaceViewAdapter

activityRule.scenario.onActivity { activity ->
savedPlaceRecyclerView =
activity.findViewById<RecyclerView>(R.id.saved_search_recyclerView)
savedPlaceAdapter = savedPlaceRecyclerView.adapter as SavedPlaceViewAdapter

savedPlace = (savedPlaceAdapter.getSavedPlaceAtPosition(0))
existTaget = savedPlaceAdapter.existPlace(savedPlace)
assertTrue(existTaget)
}

onView(withId(R.id.saved_search_recyclerView)).perform(
actionOnItemAtPosition<PlaceViewHolder>(0, MyViewAction.clickChildViewWithId(R.id.button_saved_delete))
)
Thread.sleep(1000)

activityRule.scenario.onActivity { activity ->
existTaget = savedPlaceAdapter.existPlace(savedPlace)
assertFalse(existTaget)
}


}
object MyViewAction {
fun clickChildViewWithId(id: Int): ViewAction {
return object : ViewAction {
override fun getConstraints(): org.hamcrest.Matcher<View> {
return isAssignableFrom(View::class.java)
}

override fun getDescription(): String {
return "Click on a child view with specified id."
}

override fun perform(uiController: UiController?, view: View) {
val v = view.findViewById<View>(id)
v.performClick()
}
}
}
}
}
Loading